Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Proxy і пастки get та set». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**`Proxy` це обгортка над об'єктом або функцією, яка перехоплює операції з ним: читання, запис, виклик і таке інше.** Створюють його як `new Proxy(target, handler)`, де `target` це оригінальний об'єкт, а `handler` це об'єкт з пастками (traps), тобто методами-перехоплювачами. Пастка `get(target, prop, receiver)` спрацьовує на читанні властивості і вирішує, що саме повернути: реальне значення, значення за замовчуванням або обчислену властивість. Пастка `set(target, prop, value, receiver)` спрацьовує на присвоєнні: вона може валідувати дані, заборонити запис або запустити побічний ефект, і зобов'язана повернути `true` в разі успіху. ```javascript const proxy = new Proxy({ name: 'Tim' }, { get: (target, prop) => target[prop] ?? 'No such property', }); proxy.age; // 'No such property' ``` **Ключове:** `get` перехоплює читання властивості, `set` перехоплює запис і має повернути `true`.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**`Proxy` це обгортка над об'єктом (або функцією), яка перехоплює операції з ним: читання, запис, виклик і так далі.** Проксі стоїть між об'єктом і кодом, що його використовує, і сам вирішує, як реагувати на кожну операцію. ## Теорія ### TL;DR - Синтаксис: `new Proxy(target, handler)`. - `target` це оригінальний об'єкт, з яким ми хочемо працювати. - `handler` це об'єкт з пастками (traps), спеціальними методами-перехоплювачами, які описують реакцію на різні операції. - `get` перехоплює читання властивості, `set` перехоплює запис. - Проксі дають змогу логувати доступ, валідувати дані, робити реактивні об'єкти і ховати приватні поля. - Пастка `set` має повернути `true`, інакше в strict mode буде `TypeError`. ### Швидкий приклад ```javascript const proxy = new Proxy(target, handler); ``` - `target` це оригінальний об'єкт (той, з яким ми хочемо працювати); - `handler` це об'єкт з пастками (traps), спеціальними методами-перехоплювачами, які описують, як реагувати на різні операції. ### Навіщо потрібні проксі Проксі дають змогу втручатися в базову поведінку об'єктів, наприклад: - логувати доступ до властивостей; - валідувати дані під час запису; - створювати реактивні об'єкти (саме так це працює у Vue); - автоматично підвантажувати значення; - захищати приватні дані. Приклад, логування всіх звертань до об'єкта: ```javascript const user = { name: 'Tim', age: 25 }; const proxy = new Proxy(user, { get(target, prop) { console.log(`Reading property "${prop}"`); return target[prop]; } }); console.log(proxy.name); // log: Reading property "name" ``` ### Що робить пастка `get` `get(target, prop, receiver)` спрацьовує, коли до властивості об'єкта звертаються: ```javascript proxy.name; proxy['age']; ``` Вона дає змогу: - контролювати, що повертається під час читання; - підставляти значення за замовчуванням; - робити обчислювані властивості; - ховати певні поля. Приклад: ```javascript const user = { name: 'Tim' }; const proxy = new Proxy(user, { get(target, prop) { if (prop === 'greet') { return `Hello, ${target.name}!`; } return target[prop] ?? 'No such property'; } }); console.log(proxy.name); // 'Tim' console.log(proxy.greet); // 'Hello, Tim!' console.log(proxy.age); // 'No such property' ``` ### Що робить пастка `set` `set(target, prop, value, receiver)` спрацьовує, коли ми присвоюємо значення: ```javascript proxy.age = 30; ``` Вона дає змогу: - валідувати нові дані; - забороняти запис; - автоматично змінювати значення; - викликати побічні ефекти (реактивність, логування тощо). Приклад: ```javascript const user = {}; const proxy = new Proxy(user, { set(target, prop, value) { if (prop === 'age' && typeof value !== 'number') { throw new TypeError('Age must be a number!'); } target[prop] = value; console.log(`Property "${prop}" is set to ${value}`); return true; // обов'язково повернути true, якщо все пройшло успішно } }); proxy.age = 25; // log: Property "age" is set to 25 proxy.name = 'Tim'; proxy.age = 'a lot'; // TypeError ``` ### Підсумок | Компонент | Призначення | | --- | --- | | `Proxy(target, handler)` | Створює обгортку над об'єктом | | `target` | Оригінальний об'єкт | | `handler` | Об'єкт з пастками (методами-перехоплювачами) | | `get` | Перехоплює читання властивості | | `set` | Перехоплює запис властивості | ### Типові помилки - **Забути `return true` у пастці `set`.** У strict mode, а отже і в модулях, невдале присвоєння кидає `TypeError`. - **Думати, що проксі змінює оригінальний об'єкт.** Перехоплюються лише операції, що йдуть через проксі; звертання напряму до `target` проходять повз пастки. - **Забувати, що `prop` може бути символом.** Порівняння `prop === 'age'` не спрацює для `Symbol`, тому перевіряйте тип ключа, коли це важливо. - **Писати `target[prop]` замість `Reflect.get(target, prop, receiver)`.** Прямий доступ ламає коректну роботу геттерів і успадкування, бо всередині них `this` буде не той. - **Очікувати, що пастка `get` спрацює на `JSON.stringify` так само, як на звичайному об'єкті.** Серіалізація теж іде через пастки, тому обчислені поля можуть несподівано потрапити у вивід. - **Ставити проксі там, де достатньо звичайних геттерів і сеттерів.** Проксі дорожчий за викликом і помітно ускладнює налагодження.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.