Reflect 配合proxy 使對象的操做更加函數化。javascript
大部分Reflect 的全局方法或者說靜態方法與proxy一致。java
相比Object 返回值更合理:修改某些Object
方法的返回結果,讓其變得更合理。好比,Object.defineProperty(obj, name, desc)
在沒法定義屬性時,會拋出一個錯誤,而Reflect.defineProperty(obj, name, desc)
則會返回false
。app
若是 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
攔截。this
Reflect.construct: 等同於new target(args) 建立實例對象。spa
function Greeting(name) { this.name = name; } // new 的寫法 const instance = new Greeting('張三'); // Reflect.construct 的寫法 const instance = Reflect.construct(Greeting, ['張三']);
若是Reflect.construct()
方法的第一個參數不是函數,會報錯。prototype
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
會報錯。code
Reflect.apply(): 若是要綁定一個函數的this
對象,能夠這樣寫fn.apply(obj, args)
,可是若是函數定義了本身的apply
方法,就只能寫成Function.prototype.apply.call(fn, obj, args)
,採用Reflect
對象能夠簡化這種操做。server
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