Proxy
иReflect
Новый API для ES6.
Reflect
Reflect
— это встроенный объект, предоставляющий методы для перехвата операций JavaScript. Reflect не является функциональным объектом, поэтому его нельзя построить.Reflect
Все методы являются статическими, насколькоMath
Опять же, в настоящее время он не имеет статических свойств.
Reflect
методы объекта иProxy
Метод объекта тот же.
Reflect
Всего существует 13 статических методов:
его можно разделить на части, которые изначально существовалиObject
метод выше, экранируйте его, чтобыReflect
, и внес небольшие изменения, чтобы сделать метод более разумным.
-
defineProperty
иObject.definePropertyАналогично, но когда объект не может быть определенObject.defineProperty
сообщит об ошибкеReflect.defineProperty
нет, вернетсяfalse
, отдача от успехаtrue
, если это не объект, он все равно сообщит об ошибке. -
getPrototypeOf(target)
иObject.getPrototypeOf
Мол, возвращает прототип указанного объекта. -
setPrototypeOf(target, prototype)
иObject.setPrototypeOf
Например, он устанавливает прототип указанного объекта в другой объект. -
getOwnPropertyDescriptor()
иObject.getOwnPropertyDescriptor
Например, если он существует в объекте, возвращает значение данного свойства.дескриптор свойства. -
isExtensible(target)
иObject.isExtensible
Точно так же, чтобы определить, является ли объект расширяемым (можно ли добавить к нему новые свойства), их отличие состоит в том, что, когда параметр не является объектом (исходным значением),Object
принуждать его к объекту,Reflect
является прямой ошибкой. -
preventExtensions(target)
иObject.preventExtensions
Точно так же запретите добавление новых свойств к объекту, разница такая же, как и предыдущая. -
apply(func, thisArg, args)
иFunction.prototype.apply.call(fn, obj, args)
Такой же. -
ownKeys(target)
иObject.getOwnPropertyNames(target).concat(Object.getOwnPropertySymbols(target))
то же самое, возвращает массив, содержащий все собственные свойства (за исключением унаследованных свойств)
Другая часть состоит в том, чтобы превратить функцию исходного оператора в поведение функции.
-
has(target, key)
иin
Подобно оператору, пусть операция суждения станет поведением функции. -
deleteProperty(target, key)
иdelete
Как и оператор, он превращает операцию удаления в поведение функции, которая возвращает логическое значение, представляющее успех или неудачу. -
construct(target, argumentsList[, newTarget])
иnew
оператор,target
Конструктор, второй параметр — это массив параметров конструктора класса, а третий —new.targetзначение . -
get(target, key[, receiver])
иobj[key]
То же самое, третий параметр - когда брать значениеkey
развернутыйgetter
при доступе к его функцииthis
связывать какreceiver
объект. -
set(target, key, value[, receiver])
настраиватьtarget
объектkey
свойство равноvalue
, третий параметр иset
Такой же. Возвращает логическое значение.
// 老写法
'assign' in Object // true
// 新写法
Reflect.has(Object, 'assign') // true
// 老写法
Function.prototype.apply.call(Math.floor, undefined, [1.75]) // 1
// 新写法
Reflect.apply(Math.floor, undefined, [1.75]) // 1
// 旧写法
delete myObj.foo;
// 新写法
Reflect.deleteProperty(myObj, 'foo');
// new 的写法
const instance = new Greeting('张三');
// Reflect.construct 的写法
const instance = Reflect.construct(Greeting, ['张三']);
// 旧写法
Object.defineProperty(MyDate, 'now', {
value: () => Date.now()
});
// 新写法
Reflect.defineProperty(MyDate, 'now', {
value: () => Date.now()
});
Reflect.get(1, 'foo') // 报错
Reflect.get(false, 'foo') // 报错
Reflect.set(1, 'foo', {}) // 报错
Reflect.set(false, 'foo', {}) // 报错
// ---------------
var myObject = {
foo: 1,
bar: 2,
get baz() {
return this.foo + this.bar;
},
};
var myReceiverObject = {
foo: 4,
bar: 4,
};
Reflect.get(myObject, 'baz', myReceiverObject) // 8
Proxy
Прокси-объекты используются для определения настраиваемого поведения для основных операций (таких как поиск свойств, присвоение, перечисление, вызовы функций и т. д.), которые эквивалентны внесению изменений на уровне языка, поэтому они относятся к своего рода «метапрограммированию». , то есть на язык программирования для программирования.
Прокси подобен прокси между целевыми объектами, любая операция над целью должна проходить через прокси. Прокси может фильтровать и переписывать операции внешнего мира.
Proxy
это конструктор, он принимает два параметраtarget
иhandler
,
target
Обернут ли целевой объект прокси-сервером (может быть объект любого типа, включая собственные массивы, функции или даже другой прокси-сервер).
handler
— это объект, свойствами которого являются функции, определяющие поведение агента при выполнении операции.
var obj = new Proxy({}, {
get: function (target, key, receiver) {
console.log(`getting ${key}!`);
return Reflect.get(target, key, receiver);
},
set: function (target, key, value, receiver) {
console.log(`setting ${key}!`);
return Reflect.set(target, key, value, receiver);
}
});
obj.count = 1
// setting count!
++obj.count
// getting count!
// setting count!
// 2
Proxy
только один статический методrevocable(target, handler)
Может использоваться для создания отзывного прокси-объекта. Эти два параметра такие же, как у конструктора. Он возвращает объект, содержащий сам сгенерированный прокси-объект и метод отмены для прокси-объекта.
Как только прокси-объект будет отозван, он станет почти полностью недоступным, и выполнение любой прокси-операции с ним вызовет исключение TypeError (обратите внимание, что существует 14 типов прокси-операций, и операции, отличные от этих 14, не вызовут исключение). исключение). После отзыва прокси-объект никогда не может быть восстановлен в исходное состояние, а целевой объект и объект процессора, связанный с ним, скорее всего, будут удалены сборщиком мусора. Многократный вызов метода отмены не будет иметь никакого эффекта, и, конечно же, не будет сообщено об ошибке.
var revocable = Proxy.revocable({}, {
get(target, name) {
return "[[" + name + "]]";
}
});
// revocable -> {"proxy": proxy, "revoke": revoke}
var proxy = revocable.proxy;
proxy.foo; // "[[foo]]"
revocable.revoke(); // 执行撤销方法
proxy.foo; // TypeError
proxy.foo = 1 // 同样 TypeError
delete proxy.foo; // 还是 TypeError
typeof proxy // "object",因为 typeof 不属于可代理操作
handler
Параметр представляет собой объект прокси-функции, который поддерживает в общей сложности 13 функций перехвата. иReflect
то же. Если операция не определена, операция будет переадресована целевому объекту.
const proxy = new Proxy({}, {
get: function(target, property, receiver) {
return receiver;
// receiver 总是指向原始的读操作所在的那个对象,一般情况下就是 Proxy 实例。
}
});
proxy.getReceiver === proxy // true
Если свойство не настраивается и недоступно для записи, прокси-сервер не может изменить свойство, в противном случае доступ к свойству через объект-прокси вызовет ошибку.
const target = Object.defineProperties({}, {
foo: {
value: 123,
writable: false,
configurable: false
},
});
const handler = {
get(target, propKey) {
return 'abc';
}
};
const proxy = new Proxy(target, handler);
proxy.foo
// TypeError: Invariant check failed
apply
перехватчик метода调用
,call
иapply
работать.
var target = function () { return 'I am the target'; };
var handler = {
apply: function () {
return 'I am the proxy';
}
};
var p = new Proxy(target, handler);
p()
// "I am the proxy"
defineProperty
метод заблокированObject.defineProperty
работать.
var handler = {
defineProperty (target, key, descriptor) {
return false;
}
};
var target = {};
var proxy = new Proxy(target, handler);
proxy.foo = 'bar' // 不会生效
// defineProperty 方法返回 false,导致添加新属性总是无效。
Обратите внимание, что если целевой объект не является расширяемым, defineProperty не может добавлять свойства, которых нет в целевом объекте, иначе будет сообщено об ошибке. Кроме того, если свойство целевого объекта недоступно для записи или настройки, метод defineProperty не должен изменять эти два параметра.
getPrototypeOf
Метод в основном используется для перехвата и получения прототипа объекта, который будет выполнять следующие операции:
Object.prototype.__proto__
Object.prototype.isPrototypeOf()
Object.getPrototypeOf()
Reflect.getPrototypeOf()
instanceof
ownKeys
Метод используется для перехвата операции чтения собственных свойств объекта, которая будет перехватывать следующие операции:
Object.getOwnPropertyNames()
Object.getOwnPropertySymbols()
Object.keys()
for...in
С прокси вы можете легко проверять значения, передаваемые объекту.
let validator = {
set: function(obj, prop, value) {
if (prop === 'age') {
if (!Number.isInteger(value)) {
throw new TypeError('The age is not an integer');
}
if (value > 200) {
throw new RangeError('The age seems invalid');
}
}
// The default behavior to store the value
obj[prop] = value;
}
};
let person = new Proxy({}, validator);
person.age = 100;
console.log(person.age);
// 100
person.age = 'young';
// 抛出异常: Uncaught TypeError: The age is not an integer
person.age = 300;
// 抛出异常: Uncaught RangeError: The age seems invalid
это указывает на
Хотя Proxy может проксировать доступ к целевому объекту, он не является прозрачным прокси для целевого объекта, то есть без какого-либо перехвата он не может гарантировать такое же поведение, как и целевой объект. Основная причина в том, что в случае с прокси-сервером внутреннийthis
Ключевое слово будет указывать на прокси-сервер.
const target = {
m: function () {
console.log(this === proxy);
}
};
const handler = {};
const proxy = new Proxy(target, handler);
target.m() // false
proxy.m() // true
const target = new Date();
const handler = {};
const proxy = new Proxy(target, handler);
proxy.getDate();
// TypeError: this is not a Date object.
// getDate 方法只能在Date对象实例上面拿到,
// 如果this不是Date对象实例就会报错。
// 这时,this绑定原始对象,就可以解决这个问题
const target = new Date('2015-01-01');
const handler = {
get(target, prop) {
if (prop === 'getDate') {
return target.getDate.bind(target);
}
return Reflect.get(target, prop);
}
};
const proxy = new Proxy(target, handler);
proxy.getDate() // 1