ES6 Reflect

一、概述

  • Reflect對象與Proxy對象一樣,也是 ES6 為了操作對象而提供的新 API。Reflect對象的設計目的有這樣幾個。

  • Reflect 可以用于獲取目標對象的行為,它與 Object 類似,但是更易讀,為操作對象提供了一種更優(yōu)雅的方式。它的方法與 Proxy 是對應的。

(1) Object對象的一些明顯屬于語言內部的方法(比如Object.defineProperty),放到Reflect對象上。現階段,某些方法同時在ObjectReflect對象上部署,未來的新方法將只部署在Reflect對象上。也就是說,從Reflect對象上可以拿到語言內部的方法。

(2) 修改某些Object方法的返回結果,讓其變得更合理。比如,Object.defineProperty(obj, name, desc)在無法定義屬性時,會拋出一個錯誤,而Reflect.defineProperty(obj, name, desc)則會返回false。

// 老寫法
try {
  Object.defineProperty(target, property, attributes);
  // success
} catch (e) {
  // failure
}

// 新寫法
if (Reflect.defineProperty(target, property, attributes)) {
  // success
} else {
  // failure
}

(3) Object操作都變成函數行為。某些Object操作是命令式,比如name in objdelete obj[name],而Reflect.has(obj, name)Reflect.deleteProperty(obj, name)讓它們變成了函數行為。

// 老寫法
'assign' in Object // true

// 新寫法
Reflect.has(Object, 'assign') // true

(4)Reflect對象的方法與Proxy對象的方法一一對應,只要是Proxy對象的方法,就能在Reflect對象上找到對應的方法。這就讓Proxy對象可以方便地調用對應的Reflect方法,完成默認行為,作為修改行為的基礎。也就是說,不管Proxy怎么修改默認行為,你總可以在Reflect上獲取默認行為。

例子1:

Proxy(target, {
  set: function(target, name, value, receiver) {
    var success = Reflect.set(target, name, value, receiver);
    if (success) {
      console.log('property ' + name + ' on ' + target + ' set to ' + value);
    }
    return success;
  }
});

上面代碼中,Proxy方法攔截target對象的屬性賦值行為。它采用Reflect.set方法將值賦值給對象的屬性,確保完成原有的行為,然后再部署額外的功能。

例子2:

var loggedObj = new Proxy(obj, {
  get(target, name) {
    console.log('get', target, name);
    return Reflect.get(target, name);
  },
  deleteProperty(target, name) {
    console.log('delete' + name);
    return Reflect.deleteProperty(target, name);
  },
  has(target, name) {
    console.log('has' + name);
    return Reflect.has(target, name);
  }
});

上面代碼中,每一個Proxy對象的攔截操作(get、deletehas),內部都調用對應的Reflect方法,保證原生行為能夠正常執(zhí)行。添加的工作,就是將每一個操作輸出一行日志。

  • 有了Reflect對象以后,很多操作會更易讀。
// 老寫法
Function.prototype.apply.call(Math.floor, undefined, [1.75]) // 1

// 新寫法
Reflect.apply(Math.floor, undefined, [1.75]) // 1

二、靜態(tài)方法

  • 這些方法的作用,大部分與Object對象的同名方法的作用都是相同的,而且它與Proxy對象的方法是一一對應的。

Reflect對象一共有 13 個靜態(tài)方法。

  1. Reflect.get(target, name, receiver):查找并返回target對象的name屬性,如果沒有該屬性,則返回undefined。
  2. Reflect.set(target, name, value, receiver):設置target對象的name屬性等于value。
  3. Reflect.has(target, name):對應name in obj里面的in運算符。
  4. Reflect.deleteProperty(target, name):等同于delete obj[name],用于刪除對象的屬性。
  5. Reflect.ownKeys(target):用于返回對象的所有屬性,基本等同于Object.getOwnPropertyNames與Object.getOwnPropertySymbols之和。
  6. Reflect.getOwnPropertyDescriptor(target,name):基本等同于Object.getOwnPropertyDescriptor,用于得到指定屬性的描述對象,將來會替代掉后者。
  7. Reflect.defineProperty(target, name,desc):基本等同于Object.defineProperty,用來為對象定義屬性。未來,后者會被逐漸廢除,請從現在開始就使用Reflect.defineProperty代替它。
  8. Reflect.preventExtensions(target):對應Object.preventExtensions方法,用于讓一個對象變?yōu)椴豢蓴U展。它返回一個布爾值,表示是否操作成功。
  9. Reflect.getPrototypeOf(target):用于讀取對象的proto屬性,對應Object.getPrototypeOf(obj)。
  10. Reflect.isExtensible(target):對應Object.isExtensible,返回一個布爾值,表示當前對象是否可擴展。
  11. Reflect.setPrototypeOf(target,prototype):用于設置目標對象的原型(prototype),對應Object.setPrototypeOf(obj, newProto)方法。它返回一個布爾值,表示是否設置成功。
  12. Reflect.apply(target, thisArg, args):等同于Function.prototype.apply.call(func, thisArg, args),用于綁定this對象后執(zhí)行給定函數。
  13. Reflect.construct(target, args):等同于newtarget(…args),這提供了一種不使用new,來調用構造函數的方法。

三、實例:使用 Proxy 實現觀察者模式

觀察者模式(Observer mode)指的是函數自動觀察數據對象,一旦對象有變化,函數就會自動執(zhí)行。

const person = observable({   //數據對象person
  name: '張三',
  age: 20
});

function print() {    //觀察者print
  console.log(`${person.name}, ${person.age}`)
}

observe(print);
person.name = '李四';
// 輸出
// 李四, 20

上面代碼中,數據對象person是觀察目標,函數print是觀察者。一旦數據對象發(fā)生變化,print就會自動執(zhí)行。

觀察者模式實現:

使用 Proxy 寫一個觀察者模式的最簡單實現,即實現observableobserve這兩個函數。

思路是observable函數返回一個原始對象的 Proxy 代理,攔截賦值操作,觸發(fā)充當觀察者的各個函數。

const queuedObservers = new Set();  //先定義了一個Set集合

const observe = fn => queuedObservers.add(fn);  
const observable = obj => new Proxy(obj, {set});  //observable函數返回原始對象的代理

function set(target, key, value, receiver) {
  const result = Reflect.set(target, key, value, receiver);
  queuedObservers.forEach(observer => observer());
  return result;
}

上面代碼中,

  1. 先定義了一個Set集合,所有觀察者函數都放進這個集合。
  2. 然后,observable函數返回原始對象的代理,攔截賦值操作。
  3. 攔截函數set之中,會自動執(zhí)行所有觀察者。
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 本人自學es6已經有一段時間了,只覺得有些時候很是枯燥無味, 時而又覺得在以后的職業(yè)生涯中會很有用,因為es6的很...
    可樂_37d3閱讀 1,659評論 0 0
  • 概述 Reflect 對象是一個全局的普通的對象。Reflect 的原型就是 Object。我們來驗證下 Refl...
    前端_Fn閱讀 629評論 0 0
  • 1.概述 Reflect對象和Proxy對象一樣,也是ES6為了操作對象而提供新的API,Reflect對象的設計...
    前端mamba24閱讀 253評論 0 0
  • Reflect對象與Proxy對象一樣,也是 ES6 為了操作對象而提供的新 API。Reflect對象的設計目的...
    SunshineBrother閱讀 467評論 0 2
  • Reflect對象與Proxy對象一樣,也是 ES6 為了操作對象而提供的新 API Reflect對象的設計目的...
    coderfl閱讀 232評論 0 0

友情鏈接更多精彩內容