Що робить 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 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 | Дозволяє викликати стандартну поведінку "за замовчуванням" |
Коротка відповідь
Для співбесідиPremium
Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.