handler.getOwnPropertyDescriptor():在获取代理对象某个属性的属性描述时触发该操作,比如在执行Object.getOwnPropertyDescriptor(proxy, 'foo')时
handler.defineProperty():在定义代理对象某个属性时的属性描述时触发该操作,比如在执行Object.defineProperty(proxy,'foo',{})时
handler.has():在判断代理对象是否拥有某个属性时触发该操作,比如在执行'foo' in proxy时
handler.get():在读取代理对象的某个属性时触发该操作,比如在执行proxy.foo时
handler.set():在给代理对象的某个赋值时触发该操作,比如在执行proxy.foo = 1时
handler.deleteProperty():在删除代理对象的某个属性时触发该操作,比如在执行delete proxy.foo时
handler.ownKeys():在获取代理对象的所有属性键时触发该操作,比如在执行Object.getOwnPropertyNames(proxy)时
handler.apply():在调用一个目标对象为函数的代理对象时触发该操作,比如在执行proxy()时
handler.construct():在给一个目标对象为构造函数的代理对象构造实例时触发该操作,比如在执行new proxy()时
Reflect对象拥有对应的可以控制各种元编程任务的静态方法。这些功能和Proxy一一对应。
下面的这些名称你可能看起来很眼熟(因为他们也是Object上的方法):
Reflect.getOwnPropertyDescriptor(..)
Reflect.defineProperty(..)
Reflect.getPrototypeOf(..)
Reflect.setPrototypeOf(..)
Reflect.preventExtensions(..)
Reflect.isExtensible(..)
这些方法和在Object上的同名方法一样。然后,一个区别在于,Object上这么方法的第一个参数是一个对象,Reflect遇到这种情况会扔出一个错误。
3. 陷阱代理
使用set陷阱验证属性
假设创建一个属性值是数字的对象,对象中每新增一个属性都要加以验证,如果不是数字必须抛出错误。为了实现这个任务,可以定义一个set陷阱来覆写设置值的默认特性。
set陷阱接受4个参数:
trapTaqget 用于接收属性(代理的目标)的对象
key 要写入的属性键(字符串或Symbol类型)
value 被写入属性的值
receiver 操作发生的对象(通常是代理)
Reflect.set()是set陷阱对应的反射方法和默认特性,它和set代理陷阱一样也接受相同的4个参数,以方便在陷阱中使用。如果属性已设置陷阱应该返回true,如果未设置则返回false。(Reflect.set()方法基于操作是否成功来返回恰当的值)。
可以使用set陷阱并检查传入的值来验证属性值:
1 //set陷阱并检查传入的值来验证属性值
2 let target = { name: "target" };
3 let proxy = new Proxy(target, {
4 set(trapTarget, key, value, receiver) {
5 // 忽略已有属性,避免影响它们
6 if (!trapTarget.hasOwnProperty(key)) {
7 if (isNaN(value)) { throw new TypeError("Property must be a number."); }
8 } // 添加属性
9 return Reflect.set(trapTarget, key, value, receiver);
10 }
11 });
12 // 添加一个新属性
13 proxy.count = 1;
14 console.log(proxy.count); // => 1