Proxy и Reflect
Proxy перехватывает операции над объектом, Reflect даёт «правильный» способ их выполнить.
Proxy — обёртка над объектом, перехватывающая базовые операции (чтение, запись, удаление) через ловушки (traps). Reflect — набор методов, повторяющих эти операции.
Ловушки get и set
new Proxy(target, handler) создаёт прокси: все операции идут через handler. Ловушка get перехватывает чтение, set — запись. Это удобно для валидации, значений по умолчанию, логирования:
const target = { name: "книга", price: 100 };
const handler = {
get(obj, prop) {
if (prop in obj) return obj[prop];
return "нет такого свойства: " + String(prop);
},
set(obj, prop, value) {
if (prop === "price" && typeof value !== "number") {
throw new TypeError("цена должна быть числом");
}
obj[prop] = value;
return true;
}
};
const p = new Proxy(target, handler);
console.log(p.name);
console.log(p.unknown);
p.price = 150;
console.log(p.price);
try { p.price = "дорого"; } catch (e) { console.log("ошибка:", e.message); }Вывод:
книга нет такого свойства: unknown 150 ошибка: цена должна быть числом
Прокси вернул значение по умолчанию для несуществующего свойства и заблокировал запись неправильного типа в price. Ловушка set обязана вернуть true при успехе.
Reflect — операции как функции
Reflect предоставляет те же базовые операции в виде обычных функций: Reflect.get, Reflect.set, Reflect.has, Reflect.ownKeys и т.д. Они возвращают результат, а не бросают исключения там, где это неуместно:
const obj = { a: 1 };
console.log(Reflect.has(obj, "a"));
Reflect.set(obj, "b", 2);
console.log(Reflect.get(obj, "b"));
console.log(Reflect.ownKeys(obj).join(", "));
Reflect.deleteProperty(obj, "a");
console.log(Reflect.ownKeys(obj).join(", "));Вывод:
true 2 a, b b
Proxy + Reflect: правильная пара
Внутри ловушек принято вызывать соответствующий метод Reflect: он выполняет «дефолтное» поведение операции и корректно прокидывает аргументы (включая receiver для геттеров). Логирующий прокси:
function loggable(obj) {
return new Proxy(obj, {
get(target, prop, receiver) {
console.log("читаем:", String(prop));
return Reflect.get(target, prop, receiver);
}
});
}
const user = loggable({ name: "Ник", role: "admin" });
console.log("->", user.name);
console.log("->", user.role);Вывод:
читаем: name -> Ник читаем: role -> admin
Где применяют
- Реактивность (Vue 3 строит реактивность именно на
Proxy). - Валидация и схемы данных, значения по умолчанию.
- Логирование, профилирование, ленивая загрузка свойств.
Итог
Proxyперехватывает операции через ловушки (get,set, ...).Reflectдаёт те же операции как функции — вызывайте их внутри ловушек.- Связка применяется в реактивности, валидации и логировании.