什么是反射和代理?
反射 :ES6 的反射 API 以 Reflect 对象的形式出现,对象每个方法都与对应的陷阱函数同名,并且接收的参数也与之一致。
代理 :代理是用来替代另一个对象(target),JS 通过new Proxy()创建一个目标对象的代理,该代理与该目标对象表面上可以被当作同一个对象来对待。
代理陷阱 | 覆写的特性 | 默认特性 |
---|---|---|
get | 读写一个属性值 | Reflect.get() |
set | 写入一个属性 | Reflect.set() |
has | in操作 | Reflect.has() |
deleteProperty | delete操作符 | Reflect.deleteProperty() |
getAPrototypeof | Object.getAPrototypeof () | Reflect.getAPrototypeof () |
setAPrototypeof | Object.setAPrototypeof () | Reflect.setAPrototypeof () |
isExtensible | Object.isExtensible() | Reflect.isExtensible() |
preventExtensions | Object.preventExtensions() | Reflect.preventExtensions() |
getOwnPropertyDescriptor | Object.getOwnPropertyDescriptor() | Reflect.getOwnPropertyDescriptor() |
defineaProperty | Object.defineaProperty() | Reflect.defineaProperty() |
ownKeys Object.keys() | Object.getOwnPropertyNames()和 Object.getOwnPropertySysmbols() | Reflect.ownKeys() |
apply | 调用一个函数 | Reflect.apply() |
construct | 用new调用一个函数 | Reflect.construct() |
代理
当你使用 Proxy 构造器来创建一个代理时,需要传递两个参数:目标对象(target)以及一个处理器( handler),下面我们创建一个简单的代理。
// 目标对象
let target = {};
// 代理对象
let proxy = new Proxy(target, {});
proxy.name = "hello";
console.log(proxy.name); // "hello"
console.log(target.name); // "hello"
target.name = "world";
console.log(proxy.name); // "world"
console.log(target.name); // "world
proxy.name = ‘hello’; 将hello赋值给proxy.name时,代理就会将该操作转发给目标,执行name属性的创建;然而他只是做转发而不会存储该属性;所以他们之间存在一个相互引用;tartget .name设置一个新值后,proxy.name值也改变了;
set 验证对象属性的存储
如果想要创建一个对象,并要求其属性值只能是数值,这就意味着该对象的每个新增属性
都要被验证,并且在属性值不为数值类型时应当抛出错误。
这时需要使用 set 陷阱函数来拦截传入的 value,该陷阱函数能接受四个参数:
trapTarget :将接收属性的对象( 即代理的目标对象)
key :需要写入的属性的键( 字符串类型或符号类型)
value :将被写入属性的值;
receiver :操作发生的对象( 通常是代理对象)
set 陷阱对应的反射方法和默认特性是Reflect.set(),和陷阱函数一样接受这四个参数,并会基于操作是否成功而返回相应的结果
llet targetObj = {};
let proxyObj = new Proxy(targetObj, {
set: set
});
/* 定义 set 陷阱函数 */
function set (trapTarget, key, value, receiver) {
if (isNaN(value)) {
throw new TypeError("Property " + key + " must be a number.");
}
return Reflect.set(trapTarget, key, value, receiver);
}
proxyObj.count = 1;
console.log(proxyObj.count); // 1
console.log(targetObj.count); // 1
proxyObj.anotherName = "proxy" // TypeError
get 验证对象属性的读取
get 陷阱函数会在读取属性时被调用,即使该属性在对象中并不存在,它能接受三个参数:
trapTarget :将会被读取属性的对象( 即代理的目标对象)
key :需要读取的属性的键( 字符串类型或符号类型)
receiver :操作发生的对象( 通常是代理对象)
Reflect.get()方法接受与之相同的参数,并返回默认属性的默认值。
let proxyObj = new Proxy(targetObj, {
set: set,
get: get
});
/* 定义 get 陷阱函数 */
function get(trapTarget, key, receiver) {
if (!(key in receiver)) {
throw new TypeError("Property " + key + " doesn't exist.");
}
return Reflect.get(trapTarget, key, receiver);
}
console.log(proxyObj.count); // 1
console.log(proxyObj.newcount) // TypeError