vue數據雙向綁定是通過數據劫持結合發佈者-訂閱者模式的方式來實現的,我們可以先來看一下通過控制檯輸出一個定義在vue初始化數據上的對象是什麼。
var vm = new Vue({
data: {
obj: {
a: 1
}
},
created: function () {
console.log(this.obj);
}
});
結果:
我們可以看到屬性a有兩個相對應的get和set方法,爲什麼會多出這兩個方法呢?因爲vue是通過Object.defineProperty()來實現數據劫持的。
Object.defineProperty( )是用來做什麼的?它可以來控制一個對象屬性的一些特有操作,比如讀寫權、是否可以枚舉,這裏我們主要先來研究下它對應的兩個描述屬性get和set,如果還不熟悉其用法,請點擊這裏查看更多用法。
在平常,我們很容易就可以打印出一個對象的屬性數據:
var Book = {
name: 'JavaScript設計模式'
};
console.log(Book.name); // JavaScript設計模式
如果想要在執行console.log(Book.name)的同時,直接給書名加上書名號,那要怎麼處理呢?或者說要通過什麼監聽對象 Book 的屬性值。這時候Object.defineProperty( )就派上用場了,代碼如下:
var Book = {}
var name = '';
Object.defineProperty(Book, 'name', {
set: function (value) {
name = value;
console.log('書名叫' + value);
},
get: function () {
return '《' + name + '》'
}
})
Book.name = 'JavaScript設計模式'; // 書名叫JavaScript設計模式
console.log(Book.name); // 《JavaScript設計模式》
我們通過Object.defineProperty( )設置了對象Book的name屬性,對其get和set進行重寫操作,顧名思義,get就是在讀取name屬性這個值觸發的函數,set就是在設置name屬性這個值觸發的函數,所以當執行 Book.name = ‘JavaScript設計模式’ 這個語句時,控制檯會打印出 “書名叫JavaScript設計模式”,緊接着,當讀取這個屬性時,就會輸出 “《JavaScript設計模式》”,因爲我們在get函數裏面對該值做了加工了。如果這個時候我們執行下下面的語句,控制檯會輸出什麼?
console.log(Book);
沒錯,vue就是通過這種方法來進行數據劫持的。