vue2雙向綁定原理:深入響應式原理defineProperty、watcher、get、set
響應式是什麼?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。
缺陷
在ES5中無法shim:Object.defineProperty
是 ES5 中一個無法 shim 的特性,這也就是 Vue 不支持 IE8 以及更低版本瀏覽器的原因。(shim:可以將新的API引入到舊的環境中,而且僅靠就環境中已有的手段實現);- 由於 JavaScript 的限制,Vue 不能檢測數組和對象的變化:
-
- object.defineproperty 無法監控到數組下標的變化,導致通過數組下標添加元素,無法實時響應;
- object.defineProperty 只能劫持對象的屬性,從而需要對每個對象,每個屬性進行遍歷,如果,屬性值是對象,還需要深度遍歷。