Кратко
Proxy оборачивает объект и перехватывает операции: get (чтение), set (запись), has (проверка in), apply (вызов функции). Reflect предоставляет стандартные операции JavaScript, зеркальные traps. Proxy + Reflect = метапрограммирование: валидация, логирование, реактивность.
Подробно
Создание Proxy:
const handler = {
get(target, prop) {
console.log(Чтение: ${prop});
return Reflect.get(target, prop);
},
set(target, prop, value) {
console.log(Запись: ${prop} = ${value});
return Reflect.set(target, prop, value);
}
};
const obj = { name: 'Анна' }; const proxy = new Proxy(obj, handler);
proxy.name; // Чтение: name → 'Анна' proxy.age = 25; // Запись: age = 25
Типичные traps:
- get(target, prop, receiver) — чтение свойства
- set(target, prop, value, receiver) — запись свойства
- has(target, prop) — оператор in
- apply(target, thisArg, args) — вызов функции
- construct(target, args) — оператор new
Reflect — зеркальный API: // Без Reflect (рекурсивная ловушка) get(target, prop) { return target[prop]; }
// С Reflect (рекурсия корректна) get(target, prop, receiver) { return Reflect.get(target, prop, receiver); }
Практический пример — валидация: const validator = { set(target, prop, value) { if (prop === 'age' && typeof value !== 'number') { throw new TypeError('Age must be a number'); } return Reflect.set(target, prop, value); } };
const user = new Proxy({}, validator); user.age = 25; // OK // user.age = 'двадцать пять'; // TypeError
Ментальная модель
Proxy — как охранник у двери объекта. Когда кто-то пытается прочитать свойство (get) — охранник проверяет и решает, пропустить или нет. Reflect — как инструкция для охранника: «Сделай то, что обычно делает объект, но через меня.»
Примеры
**Самый простой:**
const handler = {
get(target, prop) {
return prop in target ? target[prop] : 'не найдено';
}
};
const obj = new Proxy({ a: 1 }, handler);
console.log(obj.a); // 1
console.log(obj.b); // 'не найдено'Простейший Proxy: обработка отсутствующих свойств.
**Простой:**
// Реактивный объект
function reactive(obj, onChange) {
return new Proxy(obj, {
set(target, prop, value) {
const oldValue = target[prop];
const result = Reflect.set(target, prop, value);
if (oldValue !== value) {
onChange(prop, value, oldValue);
}
return result;
}
});
}
const state = reactive({ count: 0 }, (prop, newVal) => {
console.log(`${prop} изменился на ${newVal}`);
});
state.count = 1; // 'count изменился на 1'
state.count = 5; // 'count изменился на 5'Реактивность через Proxy — основа Vue 3 и аналогичных библиотек.
**Реальный пример:**
// Отладка: логирование всех операций
function debugProxy(obj, name) {
return new Proxy(obj, {
get(target, prop) {
console.log(`[${name}] GET ${String(prop)}`);
return Reflect.get(target, prop);
},
set(target, prop, value) {
console.log(`[${name}] SET ${String(prop)} = ${value}`);
return Reflect.set(target, prop, value);
},
has(target, prop) {
console.log(`[${name}] HAS ${String(prop)}`);
return Reflect.has(target, prop);
}
});
}
const user = debugProxy({ name: 'Анна' }, 'User');
user.name; // [User] GET name
user.age = 25; // [User] SET age = 25Proxy для отладки: логирование всех операций над объектом.
Частые ошибки
**Неправильно:** Создавать Proxy без Reflect
**Почему:** Без Reflect вызов методов оригинального объекта (target[prop]) может нарушить рекурсию.
**Правильно:** Используйте Reflect.get/set для корректной рекурсии.
**Неправильно:** Думать, что Proxy не влияет на производительность
**Почему:** Proxy добавляет перехват на каждую операцию — это медленнее прямого доступа.
**Правильно:** Proxy = метапрограммирование. Используйте только когда нужно.
Важно запомнить
- Proxy перехватывает операции над объектом
- Reflect предоставляет стандартные операции
- Типичные traps: get, set, has, apply, construct
- Proxy замедляет доступ к свойствам
- Proxy — основа реактивности (Vue 3, MobX)
Связь
Назад: Вы знаете объекты (J11) и дескрипторы свойств (JV15). Proxy перехватывает операции над объектами.
Вперёд: Следующий урок (JV8) — генераторы — функции, которые могут приостанавливаться и возобновляться.