Skip to main content

Що робить Proxy?

Що таке 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 objReflect.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Виклик через newReflect.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Дозволяє викликати стандартну поведінку "за замовчуванням"

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.