Proxy: перехват и настройка операций над объектами
Что такое Proxy и зачем он нужен? 🤔
Proxy — это мощный механизм в JavaScript, который позволяет создавать "прокси-обёртки" вокруг объектов. С его помощью можно перехватывать и настраивать базовые операции (чтение, запись, удаление свойств и другие).
Представьте, что у вас есть секретарь (прокси), который фильтрует все обращения к вашему календарю (объекту). Вы можете настроить правила: какие встречи добавлять, какие скрывать, или даже подменять информацию!
const target = { name: 'Алексей' };
const handler = {
get(target, prop) {
return prop in target ? target[prop] : 'Свойство не найдено!';
}
};
const proxy = new Proxy(target, handler);
console.log(proxy.name); // "Алексей"
console.logproxy.age); // "Свойство не найдено!"
Как создать Proxy? 🛠️
Синтаксис прост:
const proxy = new Proxy(target, handler);
target— исходный объект, который нужно обернутьhandler— объект-ловушка, содержащий методы для перехвата операций
🔥 Важно! Сам
targetне изменяется — все операции происходят через прокси. Если нужно изменить оригинал, делайте это явно в ловушках.
Основные ловушки (traps) 🎣
Вот самые полезные ловушки, которые можно определить в handler:
| Ловушка | Когда срабатывает | Пример использования |
|---|---|---|
get |
При чтении свойства | Валидация доступа |
set |
При записи свойства | Проверка значений |
has |
При операции in |
Скрытие свойств |
deleteProperty |
При удалении свойства | Запрет удаления |
apply |
При вызове функции (если target — функция) | Мемоизация |
Практические примеры ✨
1. Валидация значений
Запретим устанавливать отрицательный возраст:
const person = { name: 'Мария', age: 30 };
const validator = {
set(target, prop, value) {
if (prop === 'age' && value < 0) {
throw new Error('Возраст не может быть отрицательным!');
}
target[prop] = value;
return true;
}
};
const proxy = new Proxy(person, validator);
proxy.age = -5; // Выбросит ошибку
2. Ленивая загрузка свойств
Загружаем тяжелые данные только при обращении:
const heavyData = {
get bigData() {
console.log('Загружаем тяжелые данные...');
return /* данные из API */;
}
};
const lazyLoader = {
get(target, prop) {
return prop in target ? target[prop] : null;
}
};
const proxy = new Proxy(heavyData, lazyLoader);
console.log(proxy.bigData); // Загрузит данные только сейчас
Продвинутые техники 🚀
Proxy для функций
Можно перехватывать и вызовы функций!
function sum(a, b) {
return a + b;
}
const logger = {
apply(target, thisArg, args) {
console.log(`Вызов функции с аргументами: ${args}`);
return target.apply(thisArg, args);
}
};
const loggedSum = new Proxy(sum, logger);
loggedSum(2, 3); // Логирует вызов и возвращает 5
"Несуществующие" свойства
Создадим объект, который возвращает значения для любых свойств:
const magic = new Proxy({}, {
get(target, prop) {
return `Вы запросили: ${prop}`;
}
});
console.log(magic.anything); // "Вы запросили: anything"
console.log(magic.hello); // "Вы запросили: hello"
Ограничения и подводные камни ⚠️
- Нельзя перехватить некоторые операции (например, строгое равенство
===). - Производительность — прокси добавляют накладные расходы, не используйте их для критичного по скорости кода.
- Прозрачность —
typeof proxyвозвращает'object', как и для обычного объекта.
💡 Совет от Данилы Бежина: используйте прокси для задач высокого уровня (валидация, логирование, доступ), а не для базовой логики приложения.
Где это применяется на практике? 🌍
- Валидация данных (формы, API-ответы)
- Логирование и отладка сложных взаимодействий
- Роутеры в SPA-фреймворках
- ORM-библиотеки для ленивой загрузки данных
- Системы реактивности (как во Vue 3)
// Пример реактивности
const reactive = (obj) => {
return new Proxy(obj, {
set(target, prop, value) {
target[prop] = value;
console.log(`Изменено: ${prop} = ${value}`);
return true;
}
});
};
const state = reactive({ count: 0 });
state.count++; // Логирует: "Изменено: count = 1"
Подведём итоги 🎓
Proxy — это:
- 🔮 Виртуальный слой поверх объектов
- 🛡️ Инструмент для контроля доступа и изменений
- 🧩 Основа для сложных абстракций
- ⚖️ Баланс между мощью и производительностью
Попробуйте применить прокси в своём коде — вы удивитесь, сколько задач они могут элегантно решить!