Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Reflect.defineProperty()». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**`Reflect.defineProperty(target, propertyKey, descriptor)` визначає (створює або змінює) властивість об'єкта за заданим дескриптором і повертає булеве значення: `true`, якщо операція вдалася, і `false`, якщо ні.** Це сучасний аналог `Object.defineProperty()` з передбачуванішою поведінкою: замість викидання винятку він просто повідомляє про невдачу поверненим значенням, тому не потребує `try/catch`. Працює однаково з data-дескрипторами (`value`, `writable`, `enumerable`, `configurable`) та accessor-дескрипторами (`get`, `set`). ```javascript const frozen = Object.freeze({}); // Object.defineProperty кинув би TypeError, Reflect просто повертає false console.log(Reflect.defineProperty(frozen, 'x', { value: 1 })); // false ``` **Ключове:** та сама операція, що й `Object.defineProperty()`, але результат повертається як `true` / `false`, а не як об'єкт чи виняток.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**`Reflect.defineProperty()` визначає (додає або змінює) властивість об'єкта із заданим дескриптором і повертає булеве значення, яке вказує, чи вдалося це зробити.** Це сучасний аналог `Object.defineProperty()`, але з передбачуванішою та безпечнішою поведінкою: невдача тут є звичайним результатом, а не винятком. ## Теорія ### TL;DR - Синтаксис: `Reflect.defineProperty(target, propertyKey, descriptor)`. - Повертає `true` при успіху і `false` при невдачі, а не сам об'єкт. - При невдачі не кидає виняток, тому `try/catch` не потрібен. - Приймає і data-дескриптор (`value`, `writable`), і accessor-дескриптор (`get`, `set`). - Ключі, це рядок або `Symbol`. - Основне застосування: безпечні перевірки, метапрограмування і пастки (traps) `Proxy`. ### Швидкий приклад ```javascript const user = {}; const result = Reflect.defineProperty(user, 'name', { value: 'Maria', writable: true, enumerable: true, configurable: true }); console.log(result); // true console.log(user.name); // "Maria" ``` Те саме, що `Object.defineProperty(user, 'name', { ... })`, але з важливою відмінністю: `Reflect` не кидає помилку, а просто повертає `false`. ### Сигнатура і аргументи ```javascript Reflect.defineProperty(target, propertyKey, descriptor) ``` | Аргумент | Опис | | --- | --- | | `target` | Об'єкт, у якому потрібно визначити властивість | | `propertyKey` | Ім'я властивості (рядок або `Symbol`) | | `descriptor` | Дескриптор, тобто об'єкт з прапорцями (`value`, `writable`, `enumerable`, `configurable`, `get`, `set`) | Що повертає: - `true`, якщо властивість успішно визначено; - `false`, якщо операція не вдалася (наприклад, об'єкт захищений `Object.freeze()` або властивість неконфігурована). ### Відмінність від Object.defineProperty() | Поведінка | `Object.defineProperty()` | `Reflect.defineProperty()` | | --- | --- | --- | | Повертає | сам об'єкт | `true` / `false` | | При помилці | кидає виняток | повертає `false` | | Підходить для | звичайного коду | безпечних, «рефлективних» операцій | «Рефлективний» означає такий, що працює з внутрішніми властивостями об'єктів без викидання помилок. Безпечна перевірка на практиці: ```javascript const frozen = Object.freeze({}); try { Object.defineProperty(frozen, 'x', { value: 1 }); } catch (e) { console.log('Error:', e.message); } console.log(Reflect.defineProperty(frozen, 'x', { value: 1 })); // false, без винятку ``` `Reflect.defineProperty()` просто поверне `false` замість того, щоб кидати виняток. ### Дескриптори: data і accessor Метод однаково працює і з data-, і з accessor-дескрипторами: ```javascript const person = {}; Reflect.defineProperty(person, 'fullName', { get() { return 'Maria Koval'; }, enumerable: true }); console.log(person.fullName); // "Maria Koval" ``` Тут властивість описана геттером, а не значенням, і `Reflect.defineProperty()` приймає такий дескриптор без жодних застережень. ### Динамічне визначення властивостей і умовні перевірки Метод зручно викликати в циклі, коли набір ключів відомий лише під час виконання: ```javascript const obj = {}; ['name', 'age', 'city'].forEach(key => { Reflect.defineProperty(obj, key, { value: key.toUpperCase(), enumerable: true }); }); console.log(obj); // { name: 'NAME', age: 'AGE', city: 'CITY' } ``` Повернене значення корисне прямо в умові: ```javascript if (Reflect.defineProperty(user, 'role', { value: 'admin' })) { console.log('Property added successfully'); } else { console.log('Failed to add property'); } ``` Це зручно саме тим, що не вимагає `try/catch`: результат перевіряється як звичайний булевий вираз. ### Взаємодія з Proxy У пастці (trap) `defineProperty` об'єкта `Proxy` метод `Reflect.defineProperty` використовують, щоб делегувати поведінку за замовчуванням: ```javascript const target = {}; const proxy = new Proxy(target, { defineProperty(target, key, descriptor) { console.log(`Defining property "${String(key)}"`); return Reflect.defineProperty(target, key, descriptor); } }); proxy.x = 10; // під капотом автоматично викликає Reflect.defineProperty ``` У `Proxy` рефлективні методи (`Reflect.*`) допомагають реалізувати поведінку максимально природно: сигнатура пастки збігається з сигнатурою відповідного методу `Reflect`, а булевий результат, це саме те, що пастка має повернути. Підсумкова таблиця: | Питання | Відповідь | | --- | --- | | Що робить | Визначає (створює або змінює) властивість об'єкта із вказаним дескриптором | | Що повертає | `true` при успіху, `false` при невдачі | | Чи кидає помилки | Ні | | Чи використовує дескриптор | Так (`value`, `writable`, `configurable`, `enumerable`, `get`, `set`) | | Де застосовується | Безпечні операції, `Proxy`, метапрограмування | ### Типові помилки - **Очікувати, що метод поверне об'єкт.** `Object.defineProperty()` повертає сам об'єкт і тому ланцюжкується, а `Reflect.defineProperty()` повертає `true` / `false`. Запис `Reflect.defineProperty(obj, 'a', d).b` зламається. - **Ігнорувати повернене значення.** Оскільки винятку немає, мовчазна невдача проходить непоміченою. Якщо результат важливий, його треба перевіряти. - **Обгортати виклик у `try/catch` «про всяк випадок».** Для помилки визначення властивості це зайве: сенс `Reflect` саме в тому, щоб обійтися без винятку. Виняток тут можливий хіба що для некоректних аргументів, наприклад коли `target` не є об'єктом. - **Забувати, що прапорці за замовчуванням дорівнюють `false`.** Дескриптор `{ value: 1 }` створює властивість, яка не є `writable`, `enumerable` чи `configurable`, тож вона не потрапить у `Object.keys()` і не зміниться присвоєнням. - **Плутати з `Reflect.getOwnPropertyDescriptor()`.** Перший метод встановлює дескриптор, другий читає його.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.