Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Що робить Proxy?». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**`Proxy`** - це обгортка над об'єктом, яка дозволяє перехоплювати операції над ним (читання, запис, видалення властивостей тощо). **Ключове:** обробники перехоплення (traps) задаються в `handler`, а стандартну поведінку всередині пастки зручно викликати через `Reflect`.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення## Що таке Proxy `Proxy` - це **обгортка над об'єктом**, яка дозволяє **перехоплювати** (intercept) операції над ним. Простіше кажучи: > Proxy дає можливість "стати між" твоїм кодом і об'єктом, щоб контролювати, що відбувається при зверненні до властивостей, їх зміні та інших діях. ## Синтаксис ```javascript const proxy = new Proxy(target, handler); ``` | Параметр | Опис | | --- | --- | | `target` | вихідний об'єкт, над яким будується проксі | | `handler` | об'єкт з "пастками" (traps), що перехоплюють операції | ## Приклад 1 - базовий перехоплення get/set ```javascript const user = { name: "Tim", age: 25 }; const proxy = new Proxy(user, { get(target, prop) { console.log(`Читання властивості "${prop}"`); return target[prop]; }, set(target, prop, value) { console.log(`Зміна "${prop}" на "${value}"`); target[prop] = value; return true; // обов'язково повернути true, щоб не було помилки } }); console.log(proxy.name); // Читання властивості "name" -> "Tim" proxy.age = 26; // Зміна "age" на "26" ``` ## Приклад 2 - валідація ```javascript const user = new Proxy({}, { set(target, prop, value) { if (prop === 'age' && typeof value !== 'number') { throw new TypeError('Вік має бути числом'); } target[prop] = value; return true; } }); user.age = 30; // добре user.age = "тридцять"; // TypeError ``` ## Приклад 3 - значення "за замовчуванням" ```javascript const config = new Proxy({}, { get(target, prop) { return prop in target ? target[prop] : '- не задано -'; } }); console.log(config.host); // - не задано - config.host = 'localhost'; console.log(config.host); // localhost ``` ## Приклад 4 - захист від видалення ```javascript const secure = new Proxy({ id: 1, name: 'Admin' }, { deleteProperty(target, prop) { if (prop === 'id') { console.log('Видалення заборонено!'); return false; } delete target[prop]; return true; } }); delete secure.name; // видалиться delete secure.id; // Видалення заборонено! ``` ## Приклад 5 - логування доступу ```javascript function createLoggedObject(obj) { return new Proxy(obj, { get(target, prop, receiver) { console.log(`Доступ до властивості "${prop}"`); return Reflect.get(target, prop, receiver); } }); } const user = createLoggedObject({ name: "Tim" }); console.log(user.name); // Доступ до властивості "name" ``` > Тут використовується `Reflect` - стандартний об'єкт для безпечного виконання базових операцій з об'єктами (аналог "оригінальної поведінки", див. нижче). ## Що таке Reflect (і навіщо він потрібен з Proxy) `Reflect` - це набір методів, що відповідають усім "пасткам" `Proxy`. Він дозволяє викликати **поведінку за замовчуванням**, якщо потрібно. Наприклад: ```javascript const proxy = new Proxy(user, { get(target, prop, receiver) { console.log(`-> Читання ${prop}`); return Reflect.get(target, prop, receiver); // стандартна поведінка } }); ``` Якщо не використовувати `Reflect`, довелося б вручну писати `target[prop]`, що може зламати поведінку успадкування та `this`. ## Доступні пастки (traps) | Пастка | Що перехоплює | Аналог Reflect | | --- | --- | --- | | `get` | Читання властивості | `Reflect.get()` | | `set` | Запис властивості | `Reflect.set()` | | `has` | Перевірку `prop in obj` | `Reflect.has()` | | `deleteProperty` | Видалення `delete obj[prop]` | `Reflect.deleteProperty()` | | `ownKeys` | Отримання всіх ключів (`Object.keys`, `for...in`) | `Reflect.ownKeys()` | | `getOwnPropertyDescriptor` | Дескриптор властивості | `Reflect.getOwnPropertyDescriptor()` | | `defineProperty` | Створення/зміну властивості | `Reflect.defineProperty()` | | `preventExtensions` | Заборону додавання нових властивостей | `Reflect.preventExtensions()` | | `isExtensible` | Перевірку можливості розширення | `Reflect.isExtensible()` | | `getPrototypeOf` | Отримання прототипу | `Reflect.getPrototypeOf()` | | `setPrototypeOf` | Зміну прототипу | `Reflect.setPrototypeOf()` | | `apply` | Виклик функції | `Reflect.apply()` | | `construct` | Виклик через `new` | `Reflect.construct()` | ## Приклад 6 - перехоплення виклику функції ```javascript function sum(a, b) { return a + b; } const proxySum = new Proxy(sum, { apply(target, thisArg, args) { console.log(`Виклик функції з аргументами: ${args}`); return Reflect.apply(target, thisArg, args); } }); console.log(proxySum(2, 3)); // Виклик функції з аргументами: 2,3 -> 5 ``` ## Приклад 7 - динамічна структура (наприклад, i18n) ```javascript const dictionary = { hello: "Bonjour", world: "monde" }; const i18n = new Proxy(dictionary, { get(target, key) { if (key in target) return target[key]; return `[${key}]`; // підставимо "ключ" замість перекладу } }); console.log(i18n.hello); // Bonjour console.log(i18n.missingKey); // [missingKey] ``` ## Де Proxy реально корисний | Сценарій | Приклад використання | | --- | --- | | **Валідація даних** | Перевірка типів при записі | | **Відлагодження та логування** | Перехоплення `get`/`set` для аналізу | | **Реактивність (Vue 3)** | Відстеження змін властивостей | | **Захист і обмеження** | Заборона видалення чи модифікації властивостей | | **Локалізація / доступ за ключем** | i18n, fallback-дані | | **API-обгортки** | "розумні" динамічні об'єкти (наприклад, REST API на льоту) | ## Короткий підсумок | Термін | Опис | | --- | --- | | `Proxy` | Об'єкт, що перехоплює операції з іншим об'єктом | | `target` | Вихідний об'єкт (ціль) | | `handler` | Об'єкт з пастками (методами-перехоплювачами) | | `trap` | Метод, що перехоплює певну операцію (`get`, `set` тощо) | | `Reflect` | Дозволяє викликати стандартну поведінку "за замовчуванням" |Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.