vue2雙向繫結原理:深入響應式原理defineProperty、watcher、get、set

2022-10-08 15:01:09

響應式是什麼?Vue 最獨特的特性之一~

就是我們在頁面開發時,修改data值的時候,資料、檢視頁面需要變化的地方變化。

主要使用到哪些方法?

用 Object.defineProperty給watcher物件的每一個屬性分別定義了get和set。getter負責記錄依賴,setter負責資料攔截、對data屬性的賦值和修改dom更新。大白話就是通過資料劫持 defineProperty + 釋出訂閱者模式。

深入講解

官方原文

一個普通的 JavaScript 物件傳入 Vue 範例作為 data 選項,Vue 將遍歷此物件所有的 property,並使用 Object.defineProperty 把這些 property 全部轉為 getter/setter。 

這些 getter/setter 對使用者來說是不可見的,但是在內部它們讓 Vue 能夠追蹤依賴,在 property 被存取和修改時通知變更。這裡需要注意的是不同瀏覽器在控制檯列印資料物件時對 getter/setter 的格式化並不同,所以建議安裝 vue-devtools 來獲取對檢查資料更加友好的使用者介面。

每個元件範例都對應一個 watcher 範例,它會在元件渲染的過程中把「接觸」過的資料 property 記錄為依賴。之後當依賴項的 setter 觸發時,會通知 watcher,從而使它關聯的元件重新渲染。

 實現一個‘簡易版雙向繫結’

 1.建立一個data物件,頁面為空白,defineProperty繫結data.a。

<div id="app">
   <!-- 顯示data.a的值 -->
//{{data.a}}
  //app依賴於data中的a
</div>
<script>
    const data={a:1}
    //在vue中每一個data屬性都有一個Object.defineProperty
    Object.defineProperty(data,'a',{
      get:function(){
        console.log(`存取a`);
      },
      set:function(value){
        document.getElementById('app').innerHTML=value
     } 
})

</script>

2.測試效果

在頁面存取data值,會實時展示。當有人存取到了a屬性就會觸發get這個函數。

 

在頁面修改data值,頁面會實時展示。當有人給a進行賦值的時候就會觸發set這個函數。

data.a=10

頁面

 

 這時檢視發生變化,符合Vue雙向資料繫結的原理,即:資料=>檢視,也可以的到的是set裡面value的值是輸入的10。

缺陷

  1. 在ES5中無法shim:Object.defineProperty 是 ES5 中一個無法 shim 的特性,這也就是 Vue 不支援 IE8 以及更低版本瀏覽器的原因。(shim:可以將新的API引入到舊的環境中,而且僅靠就環境中已有的手段實現);
  2. 由於 JavaScript 的限制,Vue 不能檢測陣列和物件的變化:
    • object.defineproperty 無法監控到陣列下標的變化,導致通過陣列下標新增元素,無法實時響應;
    • object.defineProperty 只能劫持物件的屬性,從而需要對每個物件,每個屬性進行遍歷,如果,屬性值是物件,還需要深度遍歷。