前言(概念)
Vue最明顯的特性之一即是它的響應式系統,其數據模型便是普通的 JavaScript
對象。而當你讀取或寫入它們時,視圖便會進行響應操做。文章簡要闡述下其實現原理,若有錯誤,還請不吝指正。我的博客地址:hiybm.cnhtml
響應式data
<div id = "exp">{{ message }}</div>
const vm = new Vue({
el: '#exp',
data: {
message: 'This is A'
}
})
vm.message = 'This is B' // 響應式
vm._message = 'This is C' // 非響應式
複製代碼
上述代碼中,data
是Vue實例的數據對象,當實例初始化時,Vue
會遍歷 data
中的全部屬性,而且使用 Object.definePropery 把這些屬性全都轉爲 getter/setter
,從而讓 data
的屬性可以響應數據變化。另外,Object.defineProperty
是 ES5 中一個沒法 shim(墊片)
的特性,這也就是爲何 Vue 不支持 IE8 以及更低版本瀏覽器的緣由。對象必須是純粹的對象 (含有零個或多個的 key/value 鍵值對):瀏覽器 API 建立的原生對象。因此,在data
中聲明過的message
是響應式數據,而因爲_message
是在data
外使用 Vue
實例增長的數據,因此亦不屬於響應式。vue
關於Object.definePropery
Object.defineProperty()
方法會直接在一個對象上定義一個新屬性,或者修改一個對象的現有屬性,並返回這個對象。這個API是實現響應式數據的關鍵所在。react
Syntax: Object.defineProperty(obj, prop, descriptor)git
Tips: 要知道ECMAScript中有兩種屬性:數據屬性和訪問器屬性。這裏的descriptor
可取值有數據屬性和訪問器屬性。 數據屬性: 包含一個數據值的位置,在此位置能夠進行讀寫操做,有如下特性:github
[[Configurable]]
:對屬性的操做可配置性開關,如刪除,修改。默認值爲true
。[[Enumberble]]
:是否可枚舉(經過for-in
)。默認值爲true
。[[Writable]]
:可否修改屬性的值。默認值爲true
。[[value]]
:包含這個屬性的數據值
,讀取時從該位置讀,寫入時把新值存到該位置。默認值爲undefined
。訪問器屬性: 不包含數據值,包含一個函數對(getter/setter
)。特性以下:瀏覽器
[[Configurable]]
:對屬性的操做可配置性開關,如刪除,修改。默認值爲true
。[[Enumberble]]
:是否可枚舉(經過for-in
)。默認值爲true
。[[Get]]
:讀取屬性時調用的函數。默認值爲undefined
。[[Set]]
:寫入屬性時調用的函數。默認值爲undefined
。Tips: 在讀取訪問器屬性時,就會調用getter
函數,該函數負責返回有效的值;在寫入訪問器屬性時,會調用setter
函數並傳入新值,該函數負責決定如何處理數據,可是這兩個函數不必定非要同時存在。Vue
即是利用getter/setter
這一特性來實現的響應系統。 示例代碼:bash
// 定義一個book對象,_year和edition都屬於數據屬性。
var book = {
_year : 2004,
edition : 1
};
// 對book對象建立 year 訪問器屬性。
Object.defineProperty(book, "year",{
// 讀取 year 訪問器屬性時,get() 方法返回 _year 的值。
get : function () {
console.info(this._year, 'get'); // 2004
return this._year;
},
// 寫入 year 訪問器屬性時,set() 方法對新值進行操做。
set : function (newValue) {
if (newValue > 2004) {
this._year = newValue;
console.info(this._year, 'set') // 2005
this.edition += newValue - 2004;
}
}
});
// 讀取 year 訪問器屬性時會返回_year的值。
book.year;
// 寫入 year 訪問器屬性時會調用set() 函數,進行操做。
book.year = 2005;
console.info(book.edition) // 2
console.info(book) // 此處藏有彩蛋。
複製代碼
watcher
官方表述:每一個組件實例都有相應的 watcher 實例對象,它會在組件渲染的過程當中把屬性記錄爲依賴,以後當依賴項的 setter 被調用時,會通知 watcher 從新計算,從而導致它關聯的組件得以更新。ide
以下圖所示: 函數
Tips:中每一個指令/數據綁定都有一個對應的watcher
對象。其中
watcher
扮演的角色至關因而一個紐帶,這個紐帶的做用就是依賴收集。
END
文中還有部分深層細節沒有講述到,後續我也會接着更新系列文章來進一步深深深究vue底層的響應式原理,SYNT。性能
參考連接