Vue3.0數據雙向綁定Proxy探究

前言

2018年11月16日,關注vue的人都知道這個時間點發生了什麼事兒吧。vue3.0更新內容html

研究數據雙向綁定的大佬們都在開始猜想這個新機制了,用原生Proxy替換Object.definePropertyvue

1. 爲何要替換Object.defineProperty

替換不是由於很差,是由於有更好的方法使用效率更高segmentfault

Object.defineProperty的缺點:設計模式

  1. 在Vue中,Object.defineProperty沒法監控到數組下標的變化,致使直接經過數組的下標給數組設置值,不能實時響應。爲了解決這個問題,通過vue內部處理後可使用如下幾種方法來監聽數組。有關於這個說明,能夠看看這個文章 vue爲何不能檢測數組變更數組

    push()
    pop()
    shift()
    unshift()
    splice()
    sort()
    reverse()

    目前只針對以上方法作了hack處理,因此恰數組屬性是檢測不到的,有侷限性。函數

  2. Object.defineProperty只能劫持對象的屬性,所以咱們須要對每一個對象的每一個屬性進行遍歷。Vue裏,是經過遞歸以及遍歷data對象來實現對數據的監控的,若是屬性值也是對象那麼須要深度遍歷,顯然若是能劫持一個完整的對象,無論是對操做性仍是性能都會有一個很大的提高。
    而要取代它的Proxy有如下兩個優勢:性能

    1. 能夠劫持整個對象,並返回一個新對象
    2. 有13種劫持操做

2. 什麼是Proxy

Proxy是 ES6 中新增的一個特性,翻譯過來意思是"代理",用在這裏表示由它來「代理」某些操做。 Proxy 讓咱們可以以簡潔易懂的方式控制外部對對象的訪問。其功能很是相似於設計模式中的代理模式。

Proxy 能夠理解成,在目標對象以前架設一層「攔截」,外界對該對象的訪問,都必須先經過這層攔截,所以提供了一種機制,能夠對外界的訪問進行過濾和改寫。

使用 Proxy 的核心優勢是能夠交由它來處理一些非核心邏輯(如:讀取或設置對象的某些屬性前記錄日誌;設置對象的某些屬性值前,須要驗證;某些屬性的訪問控制等)。 從而可讓對象只需關注於核心邏輯,達到關注點分離,下降對象複雜度等目的。

基本用法:this

let p = new Proxy(target, handler);

參數:翻譯

target: 是用Proxy包裝的被代理對象(能夠是任何類型的對象,包括原生數組,函數,甚至另外一個代理)。
handler: 是一個對象,其聲明瞭代理target 的一些操做,其屬性是當執行一個操做時定義代理的行爲的函數。

p是Proxy對象,當其餘操做對p進行更改的時候,會執行handler對象的方法。Proxy有13種數據劫持的操做,經常使用的handler處理方法:設計

get: 讀取值,
set: 獲取值,
has: 判斷對象是否擁有該屬性,
construct: 構造函數

給個例子:

let obj = {};
 let handler = {
   get(target, property) {
    console.log(`${property} 被讀取`);
    return property in target ? target[property] : 3;
   },
   set(target, property, value) {
    console.log(`${property} 被設置爲 ${value}`);
    target[property] = value;
   }
 }

 let p = new Proxy(obj, handler);
 p.name = 'tom' //name 被設置爲 tom
 p.age; //age 被讀取 3

更多的Proxy屬性方法參考MDN Proxy

3. Proxy實現數據劫持

observe(data) {
  const that = this;
  let handler = {
   get(target, property) {
      return target[property];
    },
    set(target, key, value) {
      let res = Reflect.set(target, key, value);
      that.subscribe[key].map(item => {
        item.update();
      });
      return res;
    }
  }
  this.$data = new Proxy(data, handler);
}

這段代碼裏把代理器返回的對象代理到this.$data,即this.$data是代理後的對象,外部每次對this.$data進行操做時,實際上執行的是這段代碼裏handler對象上的方法。
注:這兒用到了reflect屬性,這也是ES6裏面的,不知道的去這兒看看吧。reflect屬性

4. 對於怎麼拼接到watcher和compile

上面說到了怎麼使用Proxy作數據劫持,怎麼結合訂閱發佈,請結合 vue2.0數據雙向綁定探究 對照着Object.defineProperty數據劫持的部分去替換看一下。其餘的設計思想估計跟以前的八九不離十。

相關文章
相關標籤/搜索