Для чего нужен объект Proxy?

Аватар пользователя Ivan Gagarinov
Ivan Gagarinov
06 апреля 2022

Этот объект нужен для каких-то дополнительных действий когда происходит взаимодействие с любым объектом. В прокси существуют несколько обработчиков-ловушек, которые срабатывают при определённых событиях. Самые популярные среди них это 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. При изменении проксированного объекта-состояния, представляющего модель, могут вызываться обработчики-рендеры. Таким образом состояние будет перерисовываться при любых изменениях.

Конечно, прокси-объект тут не единственный способ достижения подобных результатов. С тем же успехом мы могли бы использовать свой класс и методы или что-то еще. Но если объект нам не принадлежит, например, если это чужая библиотека, нам бы пришлось делать какую-то обертку над этим объектом. Прокси-объект же позволяет добавить логику непосредственно в сам объект, не меняя его интерфейс.

33 0
Аватар пользователя Рустэм Давлетов
Рустэм Давлетов
10 ноября 2022

Спасибо, Иван! :)

8 0
Аватар пользователя Илья Лукичев
Илья Лукичев
17 декабря 2024

Только вот остался открытым вопрос зачем нам делать это: "Этот объект нужен для каких-то дополнительных действий когда происходит взаимодействие с любым объектом."

Какие преимуществ мы получаем?

Почему это нельзя сделать известными способами и необходимо конструировать Прокси?

0 0

Есть что добавить? Зарегистрируйтесь

или войдите в аккаунт

Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»

Курсы по программированию в Хекслете

Программирование

Веб-разработка

Разработка, верстка и деплой сайтов и веб-приложений, трудоустройство для разработчиков

Frontend-разработка

Разработка внешнего интерфейса сайтов и веб-приложений и верстка

Создание сайтов

Разработка сайтов и веб-приложений на JS, Python, Java, PHP и Ruby on Rails

Backend-разработка

Разработка серверной части сайтов и веб-приложений

Тестирование

Ручное тестирование и автоматизированное тестирование на JS, Python, Java и PHP

Аналитика данных

Сбор, анализ и интерпретация данных на Python

Интенсивные курсы

Интенсивное обучение для продолжающих

DevOps

Автоматизация настройки локального окружения и серверов, развертывания и деплоя

Математика для программистов

Обучение разделам математики, которые будут полезны при изучении программирования

JavaScript

Разработка сайтов и веб-приложений и автоматизированное тестирование на JS

Тест-драйв

Python

Веб-разработка, автоматическое тестирование и аналитика данных на Python

Java

Веб-разработка и автоматическое тестирование на Java

PHP

Веб-разработка и автоматическое тестирование на PHP

Ruby

Разработка сайтов и веб-приложений на Ruby on Rails

Go

Курсы по веб-разработке на языке Go

Верстка

HTML

Современная верстка с помощью HTML и CSS

SQL

Проектирование базы данных, выполнение SQL-запросов и изучение реляционных СУБД

Git

Система управления версиями Git, регулярные выражения и основы командой строки

Бесплатные курсы

Бесплатные курсы по тестированию, дата-аналитике, верстке, программированию на Python, Java, PHP и JavaScript.

Базы данных

Фреймворки