Объекты II
get и set
Более гибкое создание объекта. Созданы для того, чтобы можно было высчитывать значения полей, вставлять в них логику.
const person = Object.create(
{
// object protorype
// сюда можно добавлять кастомные методы
showSomething() {
console.log('Hello, World!');
},
},
{
name: {
value: 'Leonel Messi',
// дескрипторы
enumerable: true, // по умолчанию false (не будет отображаться в цикле for)
writable: true, // чтобы можно было перезаписывать
configurable: true, // чтобы работал delete
},
birthYear: {
value: 1987,
enumerable: true,
writable: true,
},
age: {
// вычисляемое поле
// вычисление значения данного поля
get() {
return new Date().getFullYear() - this.birthYear;
},
// Будет отрабатывать данный код, когда будет присваиваться новое значение этому полю
set(value) {
alert(value);
},
},
},
);
person.age; // 36
person.age = 35; // --> alert(35)
for (let key in person) {
console.log(`${key}:`, person[key]);
if (person.hasOwnProperty) {
// если не нужно пробегаться по прототипу
}
}
Proxy и Reflect
Своего рода гибкая надстройка над объектом. Можно добавлять логику для обычных действий взаимодействия с объектамии.
Объект Proxy «оборачивается» вокруг другого объекта и может перехватывать (и, при желании, самостоятельно обрабатывать) разные действия с ним, например чтение/запись свойств и другие. Далее мы будем называть такие объекты «прокси».
Прокси используются во многих библиотеках и некоторых браузерных фреймворках.
let proxy = new Proxy(target, handler);
target– это объект, для которого нужно сделать прокси, может быть чем угодно, включая функции.handler– конфигурация прокси: объект с «ловушками» («traps»): методами, которые перехватывают разные операции, например, ловушка get – для чтения свойства из target, ловушка set – для записи свойства в target и так далее.
Проксирование объектов
// простой объект
const person = {
name: 'Vladilen',
age: 25,
job: 'Fullstack',
};
// прокси-объект принимает исходный объект
const objProxy = new Proxy(person, {
// обработчик получения данных
get(target, prop) {
if (prop === 'age') {
return target['age'] + 1;
} else {
return target[prop];
}
},
// обработчик присвоения данных
set(target, prop, value) {
if (prop in target) {
target[prop] = value;
} else {
throw new Error('No property');
}
},
// проверяет наличие полей в объекте
has(target, prop) {
return ['name', 'age', 'job'].includes(prop);
},
deleteProperty(target, prop) {
console.log('deleting ...', prop);
},
});
person.age; // 25
objProxy.age; // 26
objProxy.name = 'New name'; // поменяет исходный объект
// метод has
'name' in objProxy; // true
'contry' in objProxy; // false
// метод deleteProperty - удаляет поле из Proxy и исходного объекта
delete objProxy.age; // deleting ... age
Проксирование функ ций
const log = text => `Log: ${text}`;
const fnProxy = new Proxy(log, {
apply(target, thisArg, args) {
console.log('Calling fn...');
// работа вызова по умолчанию - можно преобразовывать return
// return target.apply(thisArg, args);
// как вариант
return target.apply(thisArg, args).toUpperCase();
},
});
log('abc'); // 'Log: abc'
fnProxy('abc'); // 'LOG: ABC'
Проксирование функций-экземпляров-класов
Допустим есть какой-либо класс
class Person {
constructor() {
this.name = name;
this.age = age;
}
}
// проксируем экземпляр этого класса
const personProxy = new Proxy(Person, {
// надстройка над constructor()
construct(target, args) {},
});
Пример Проксирование функций - дефолтные параметры
const withDefaultParams = (target, defaultValue = 0) => {
return new Proxy(target, {
get: (obj, prop) => (prop in obj ? obj[prop] : defaultValue),
});
};
const position = withDefaultParams(
{
x: 10,
y: 20,
},
0,
);
// Если поля нет в параметре, то бу дет возвращаться дефолтное значение
position.x; // 10
position.y; // 20
position.z; // 0
position.i; // 0