Прокси (proxy) в JavaScript, подборка материалов по JavaScript

6210

Что такое прокси в JavaScript?

Прокси — объект, который используется для определения нестандартного поведения базовых операций (поиск свойств, перечисления, вызов функций и т.д.).

Не очень понятно, попробуем рассмотреть на примере.

Представьте себе директора и его ассистента.

Обычно ассистент занимается почтой директора. Прежде чем передавать письмо директору, он может исправлять ошибки, добавлять ссылки с указанными в письме вещам и тому подобное.

В этом случае ассистент выступает в роли прокси, он перехватывает данные адресованые директору (цели), трансформирует их в более понятный для директора (цели) формат, и затем передает их непосредственно директору.

Или же, ассистент может сохранить время директора. Когда кто-то хочет встретиться с директором (то есть требует его времени), они сначала должны связаться с ассистентом и он учитывая определенные условия определит дату встречи, или если имеет такое право, отклонит встречу.

В том случае, если кто-то пытается встретиться с директором (целью), то ассистент (прокси) перехватывает его запрос и в зависимости от условий (спрашивают, или зачем) может предоставить доступ к директору, или может отказать, или же дать ответ самостоятельно, не беспокоя директора (цель).

Теперь переходим от теории к практике.

Код прокси в JavaScript

Примерно так выглядит базовый прокси в JS:

const target = {};
const handler = {};
const proxy = new Proxy(target, handler);

target — целевой объект, на которого работает прокси (директор из предыдущего примера)

handler — объект, содержащий свойства прокси. Другими словами, это условия, при которых прокси имеет право перехватывать данные адресованые целевому объекту;

proxy — фактически, сам объект Proxy (target, handler).

Здесь прокси не делает ничего, поскольку мы не определили никаких опций при которых он будет работать, он является проходным объектом. Поэтому вы можете свободно работать с целевым объектом через прокси без помех.

Ловушки (Traps)

Ловушками называют свойства прокси.

Когда вы определяете ловушку, вы сообщаете прокси-серверу, когда необходимо выполнять определенное действие, если ловушку не определена, то прокси по умолчанию будет пересылать данные в целевой объекта.

Чаще всего вы будете использовать ловушки get и set, которые будут получать и устанавливать другие ловушки.

Get ловушка

Ловушка Get вызывается, если вы пытаетесь получить доступ к свойству target с помощью прокси-сервера, например:

const target = {};
const handler = {
  get: (target, property) => {
    console.log(`Accessing property '${property}'`);
    return target[property];
  }
};
const proxy = new Proxy(target, handler);
proxy.a;
// виводить "Accessing property 'a'" к консоли

Get — метод, который принимает цель (целевой объект) и свойства (условия, которые мы хотим получить).

Если вы пытаетесь получить свойство «а» через прокси, то сначала будет выведено на консоль действие, которое вы выполняете и возвращено значение свойства.

Set ловушка

Set ловушка вызывается тогда, когда вы пытаетесь задать новое значение полю target через прокси.

const target = {};
const handler = {
  set: (target, property, value) => {
    console.log(`Updating property '${property}' with value
      '${value}'`);
    target[property] = value;
    return true;
  }
};
const proxy = new Proxy(target, handler);
proxy.a = 'NewValue';
// logs "Updating property 'a' with value 'NewValue'" to the console

Set — метод, который принимает три параметра:

target — целевой объект;
propery — свойство, которое мы пытаемся обновить;
value — значение которое мы придаем свойству.

В этом примере мы обновляем свойство а объекта target через прокси, эта операция перехватывается ловушкой setxy, которая регистрирует свойство, которое нужно обновить, и ее значение.

Обратите внимание, ловушка set возвращает логическое значение. true, если присваивания выполнено или false, которое вызывает TypeError, если вы находитесь в строгом режиме.

Использование прокси во избежании доступа к неопределенным свойствам (undefined)

До сих пор мы не использовали прокси для чего-нибудь особенного, полезного, давайте это исправим.

Напишем код, который поможет избежать случайного доступа к свойствами не объектов.

 

const target = {};
const handler = {
  get: (target, property) => {
    target[property] = (property in target) ? target[property] : {};
    if (typeof target[property] === 'object') {
      return new Proxy(target[property], handler);
    }
    return target[property];
  }
}
const proxy = new Proxy(target, handler);
proxy.x.y.z;

Интересная часть этого примера — get ловушка.

Она перехватывает попытку получить свойство и проверяет, существует ли свойство в целевом объекте. Если да, она задает значение свойства для самой себя (то есть ничего не выполняет), если нет, она инициализирует это свойство пустым объектом.

Затем ловушка проверяет ли свойство объектом, и возвращает он новый прокси с таким же обработчиком, но теперь объектом является target [property], поскольку прокси не распространяются на другие объекты внутри целевого объекта.

Последнее возвращаемого значения — свойство target, если она не является объектом.

Теперь когда мы пытаемся получить доступ к целевого объекта x.y.z через прокси, он не возвращает Can not read property ‘y’ of undefined, а создает объекты.

Будьте осмотрительны, этот пример был создан на скорую руку, поэтому его не проверено как следует. Для серьезного использования необходимо вложить в него больше усилий.

Больше примеров
Вы можете найти больше интересных примеров о прокси на MDN. Мне нравится пример, возвращает стандартное значение, если свойство, к которой пытались добраться, не является целью, и то, что модифицирует DOM, используя proxy set tra