Объект Proxy
Proxy
представляет объект, который позволяет перехватывать выполнение операций по отношению к некотоому объекту и переопределять его поведение. Для создания объекта Proxy
применяется конструктор Proxy()
:
const proxy = new Proxy(target, handler);
Конструктор Proxy
принимает два параметра:
target
цель создания прокси, это может быть любой объект, к которому применяетсяProxy
handler
другой объект, который определяет, какие именно операции объектаtarget
будут перехватываться и переопределяться и как именно
Рассмотрим простейший пример:
// объект, к которому применяется прокси
const target = {name: "Tom"};
// объект, который определяет, как будет переопределяться target
const handler = {};
// объект прокси
const proxy = new Proxy(target, handler);
// Tom
console.log(proxy.name);
Итак, в примере выше target
- это объект, к которому будет применяться проксирование. В данном случае этот объект имеет свойство name
.
const target = {name: "Tom"};
Далее создается пустой обработчик handler
:
const handler = {};
В принципе этот объект должен определять, как будет переопределяться объект target
. Но пока оставим его пустым.
Затем создаем объект Proxy
, передавая в его конструктор объекты target
и handler
:
const proxy = new Proxy(target, handler);
Проксирование объекта (в данном случае объекта target
) означает, что через прокси мы можем обращаться к функциональности этого объекта. И в данном случае через объект proxy мы можем обратиться к свойству name проксированного объекта target
:
// Tom
console.log(proxy.name);
И поскольку мы использовали пустой handler
, который ничего не переопределяет, то по сути прокси ведет себя как оригинальный объект target
.
Переопределение функциональности объекта
Выше мы выполнили проксирование объекта, но пока никак не переопределяли его поведение. Ключевым в данном случае является определение обработчика handler
, который может перехватывать обращения к свойствам проксированного объекта. Этот обработчик может определять два метода: get
и set
.
Метод get и получение свойств объекта
Метод get
перехватывает обращения к свойству при получении его значения и возвращает для этого свойства некоторое значение:
const handler = {
get: function(target, prop, receiver) {
return некоторое_значение;
}
};
Метод get
имеет три параметра:
target
сам проксированный объект. Благодаря этому параметру мы можем обратиться к функциональности оригинального объектаprop
название свойства, к которому идет обращениеreceiver
объектProxy
, через который выполняется проксирование
Возьмем следующий пример:
const target = {name: "Tom"};
const handler = {
get: function(target, prop, receiver) {
return "Tomas Smith";
}
};
const proxy = new Proxy(target, handler);
// Tomas Smith
console.log(proxy.name);
Здесь в обработчике handler
в методе get
возвращается строка Tomas Smith
:
get: function(target, prop, receiver) {
return "Tomas Smith";
}
Это приведет к тому, что при обращение к любому свойству прокси-объекта будет возвращаться данная строка:
// Tomas Smith
console.log(proxy.name);
Так, мы выполнили перехват обращения к свойству и простейшее переопределение. При этом мы можем обащаться и к оригинальному объекту, который проксируется:
const target = {name: "Tom"};
const handler = {
get: function(target, prop) {
return "Name: " + target.name;
}
};
const proxy = new Proxy(target, handler);
// Name: Tom
console.log(proxy.name);
Здесь обработчик возвращает строку "Name: " + target.name
, где target.name
представляет обращение к свойству name оригинального объекта. Естественно логика возвращение значения свойства может более сложной.
Но возьмем более сложный объект - с двумя свойствами:
const target = {name: "Tom", age: 37};
const handler = {
get: function(target, prop) {
return target[prop];
}
};
const proxy = new Proxy(target, handler);
// Tom
console.log(proxy.name);
// 37
console.log(proxy.age);
Здесь целевой объект имеет два свойства: name
и age
. В обработчике мы перехватываем обращение к ним, но никак его не переопределяем, а просто возвращаем значения свойств оригинального объекта:
return target[prop];
Для обращения к свойствам целевого объекта применяется синтаксис массивов. Но также мы можем проверить, к какому именно свойству идет обращение, и выполнить некоторое переопределение:
const target = {name: "Tom", age: 37};
const handler = {
get: function(target, prop) {
if(prop==="name")
return target.name.toUpperCase();
else
return target[prop];
}
};
const proxy = new Proxy(target, handler);
// TOM
console.log(proxy.name);
// 37
console.log(proxy.age);
В данном случае, если обращение идет к свойству name
, то есть к свойству, которое хранит строку, то вызываем у этой строки метод toUpperCase()
и переводим ее в верхний регистр.
Установка свойства и метод set
Метод set
перехватывает обращения к свойству при установке его значения:
const handler = {
set: function(target, property, value, receiver) {
}
};
Метод set
имеет четыре параметра:
target
оригинальный объект, к которому идет проксированиеproperty
название свойства, к которому идет обращениеvalue
устанавливаемое значениеreceiver
объектProxy
, через который выполняется проксирование
Рассмотрим на примере:
const target = {name: "Tom", age: 37};
const handler = {
set: function(target, prop, value) {
console.log(value);
target[prop] = value;
}
};
const proxy = new Proxy(target, handler);
proxy.name = "Tomas";
// Tomas
console.log(proxy.name);
proxy.age = 22;
// 22
console.log(proxy.age);
В данном примере в методе set
сначала логирруем передаваеемое свойству значение, затем устанавливаем свойство:
target[prop] = value;
Немного изменим пример:
const target = {name: "Tom", age: 37};
const handler = {
set: function(target, prop, value) {
if(prop==="age" && value < 1)
console.log("Некорректный возраст");
else
return target[prop] = value;
}
};
const proxy = new Proxy(target, handler);
proxy.name = "Tomas";
// Tomas
console.log(proxy.name);
// Некорректный возраст
proxy.age = -199;
// 37
console.log(proxy.age);
proxy.age = 22;
// 22
console.log(proxy.age);
Здесь в методе set
обработчика проверяем, если идет установка свойства age
и значение меньше 1
, то просто выводим сообщение о некорректности данных:
if(prop==="age" && value < 1)
console.log("Некорректный возраст");
Иначе передаем значение свойству оригинального объекта:
else
return target[prop] = value;