Для чего нужен объект Proxy?
Этот объект нужен для каких-то дополнительных действий когда происходит взаимодействие с любым объектом. В прокси существуют несколько обработчиков-ловушек, которые срабатывают при определённых событиях. Самые популярные среди них это get
и set
, которые срабатывают соответственно при получении свойства объекта и при установке нового значения в свойство объекта. На эти ловушки можно повесить свои обработчики.
Пример:
const handler = {
get: (target, name) => {
return name in target ?
target[name] : 37;
}
};
const p = new Proxy({}, handler);
p.a = 1;
p.b = undefined;
console.log(p.a, p.b); // 1, undefined
console.log('c' in p, p.c); // false, 37
Для чего это нужно
Например мы хотим переопределить поведение какой-то функции, чтобы она умела работать с другими типами данных или с другим количеством параметров(это называется перегрузка функции). Либо если нужно дополнительно проверять значение, которые добавляются в свойства объекта, либо например нужно вести логирование при работе с объектом. В общем, везде, где мы хотим внести дополнительную логику над объектом, может пригодиться прокси.
Чтобы было более понятно, в каких ситуациях может пригодиться Proxy, давайте разберем реальный пример. Предположим в нашем приложении используется функция вычисления какого-то результата, например вычисление факториала:
function factorial(n) {
if (n === 0) {
return 1;
}
return n * factorial(n - 1);
}
Если вы не знаете что такое факториал и вам не понятно что делает функция — это не страшно. Главное, что нам нужно тут знать, это что фукнция что-то вычисляет и делает это очень неэффективно. При передаче в функцию даже не очень высокого значения может занять значительное время вычисления. Поэтому хорошей идеей будет добавить мемоизацию в такую фукнцию, чтобы при одних и тех же параметрах функция не выполняла повторно вычисление, а возвращала сохраненный результат:
function memoize(func) {
const cache = new Map();
const handler = {
apply(target, thisArg, args) {
const key = JSON.stringify(args);
if (cache.has(key)) {
return cache.get(key);
}
const result = target.apply(thisArg, args);
cache.set(key, result);
return result;
}
};
return new Proxy(func, handler);
}
const memoizedFactorial = memoize(factorial);
memoizedFactorial(10); // 3628800
memoizedFactorial(10); // 3628800 возвращается сохрененное значение
Какие это дает преимущества?
Мы можем просто добавить нужную логику к уже существующим объектам в коде. Это позволяет добавить логику в одном месте, без переписывания использования объекта по всему коду.
Например, такой подход можно использовать для MVC. При изменении проксированного объекта-состояния, представляющего модель, могут вызываться обработчики-рендеры. Таким образом состояние будет перерисовываться при любых изменениях.
Конечно, прокси-объект тут не единственный способ достижения подобных результатов. С тем же успехом мы могли бы использовать свой класс и методы или что-то еще. Но если объект нам не принадлежит, например, если это чужая библиотека, нам бы пришлось делать какую-то обертку над этим объектом. Прокси-объект же позволяет добавить логику непосредственно в сам объект, не меняя его интерфейс.
Спасибо, Иван! :)
Только вот остался открытым вопрос зачем нам делать это: "Этот объект нужен для каких-то дополнительных действий когда происходит взаимодействие с любым объектом."
Какие преимуществ мы получаем?
Почему это нельзя сделать известными способами и необходимо конструировать Прокси?