參考版本 vue原始碼版本:0.11
相關
vue實現雙向資料繫結的關鍵是 Object.defineProperty ,讓我們先來看下這個函式。
在MDN上檢視有關 Object.defineProperty 的解釋。
我們先從最簡單的開始:
let a = {`b`: 1};
Object.defineProperty(a, `b`, {
enumerable: false,
configurable: false,
get: function(){
console.log(`b` + `被訪問`);
},
set: function(newVal){
console.log(`b` + `被修改,新` + `b` + `=` + newVal);
}
});
a.b = 2; // b被修改,新b=2
a.b; // b被訪問
這樣,我們就能監聽物件了!但問題並不僅僅這麼簡單。。。
我們可能會有物件中屬性的值還是物件這種巢狀情況,可以通過遞迴解決!
在vue原始碼檔案 srcobserveobserver.js 中
// 觀察者建構函式
function Observer(data){
this.data = data;
this.walk(data);
}
let p = Observer.prototype;
p.walk = function(obj){
let val;
for(let key in obj){
// 通過 hasOwnProperty 過濾掉一個物件本身擁有的屬性
if(obj.hasOwnProperty(key)){
val = obj[key];
// 遞迴呼叫 迴圈所有物件出來
if(typeof val === `object`){
new Observer(val);
}
this.convert(key, val);
}
}
};
p.convert = function(key, val){
Object.defineProperty(this.data, key, {
enumerable: false,
configurable: false,
get: function(){
console.log(key + `被訪問`);
},
set: function(newVal){
console.log(key + `被修改,新` + key + `=` + newVal);
if(newVal === val) return ;
val = newVal;
}
})
};
let data = {
user: {
name: `zhangsan`,
age: 14
},
address: {
city: `beijing`
}
}
let app = new Observer(data);
data.user.name; // user被訪問