Reflect 配合proxy 使对象的操作更加函数化。
大部分Reflect 的全局方法或者说静态方法与proxy一致。
相比Object 返回值更合理:修改某些Object
方法的返回结果,让其变得更合理。比如,Object.defineProperty(obj, name, desc)
在无法定义属性时,会抛出一个错误,而Reflect.defineProperty(obj, name, desc)
则会返回false
。
如果 Proxy
对象和 Reflect
对象联合使用,前者拦截赋值操作,后者完成赋值的默认行为,而且传入了receiver
,那么Reflect.set
会触发Proxy.defineProperty
拦截。
let p = { a: 'a' }; let handler = { set(target, key, value, receiver) { console.log('set'); Reflect.set(target, key, value, receiver) }, defineProperty(target, key, attribute) { console.log('defineProperty'); Reflect.defineProperty(target, key, attribute); } }; let obj = new Proxy(p, handler); obj.a = 'A'; // set // defineProperty
因为Proxy.set
的receiver
参数总是指向当前的 Proxy
实例(即上例的obj
),而Reflect.set
一旦传入receiver
,就会将属性赋值到receiver
上面(即obj
),导致触发defineProperty
拦截。如果Reflect.set
没有传入receiver
,那么就不会触发defineProperty
拦截。
Reflect.construct: 等同于new target(args) 创建实例对象。
function Greeting(name) { this.name = name; } // new 的写法 const instance = new Greeting('张三'); // Reflect.construct 的写法 const instance = Reflect.construct(Greeting, ['张三']);
如果Reflect.construct()
方法的第一个参数不是函数,会报错。
Reflect.getPrototypeOf:
用于读取对象的__proto__
属性,对应Object.getPrototypeOf(obj)
。
const myObj = new FancyThing(); // 旧写法 Object.getPrototypeOf(myObj) === FancyThing.prototype; // 新写法 Reflect.getPrototypeOf(myObj) === FancyThing.prototype;
Reflect.getPrototypeOf
和Object.getPrototypeOf
的一个区别是,如果参数不是对象,Object.getPrototypeOf
会将这个参数转为对象,然后再运行,而Reflect.getPrototypeOf
会报错。
Reflect.apply(): 如果要绑定一个函数的this
对象,可以这样写fn.apply(obj, args)
,但是如果函数定义了自己的apply
方法,就只能写成Function.prototype.apply.call(fn, obj, args)
,采用Reflect
对象可以简化这种操作。
Reflect.defineProperty:为对象定义属性。
const p = new Proxy({}, { defineProperty(target, prop, descriptor) { console.log(descriptor); return Reflect.defineProperty(target, prop, descriptor); } }); p.foo = 'bar'; // {value: "bar", writable: true, enumerable: true, configurable: true} p.foo // "bar"
Proxy.defineProperty
对属性赋值设置了拦截,然后使用Reflect.defineProperty
完成了赋值。
Reflect.preventExtensions:用于让一个对象变为不可扩展。它返回一个布尔值,表示是否操作成功。
观察者模式:使用 Proxy 写一个观察者模式的最简单实现,即实现observable
和observe
这两个函数。思路是observable
函数返回一个原始对象的 Proxy 代理,拦截赋值操作,触发充当观察者的各个函数。
const queuedObservers = new Set(); const observe = fn => queuedObservers.add(fn); const observable = obj => new Proxy(obj, {set}); function set(target, key, value, receiver) { const result = Reflect.set(target, key, value, receiver); queuedObservers.forEach(observer => observer()); return result; }
首先:需要定义observable ,定义代理(添加需要被代理的对象),在执行set(例子中为set 对象的add 添加)操作时,代理对象首先在目标对象(原始对象)设置属性与值,然后循环执行观察者函数(例子中print方法)。
const person = observable({ name: '张三', age: 20 }); function print() { console.log(`${person.name}, ${person.age}`) } observe(print); person.name = '李四'; // 输出 // 李四, 20