Object.defineProperty()
該方法會直接在一個對象上定義一個新屬性括尸,或者修改一個對象的現(xiàn)有屬性闷尿, 并返回這個對象潮瓶。
例:
//在console.log(book.name)同時,直接給書加一個書號
var Book = {};
var name = '';
Object.defineProperty(Book,'name',{
set:function(value) {
name = value;
console.log('你取了一個書名叫:'+value);
},
get:function() {
console.log('get方法被監(jiān)聽到');
return '<'+name+'>';
}
});
Book.name = '人性的弱點'; //你取了一個書名叫:人性的弱點
console.log(Book.name); //<人性的弱點>
利用這個特性,vue遍歷傳入每個實例的data對象
源碼
//遍歷傳入實例的data對象的屬性酷麦,將其設(shè)置為Vue對象的訪問器屬性
function observe(obj,vm){
Object.keys(obj).forEach(function(key){
defineReactive(vm,key,obj[key]);
});
}
//設(shè)置為訪問器屬性贯莺,并在其getter和setter函數(shù)中重慢,使用訂閱發(fā)布模式测僵。互相監(jiān)聽朴读。
function defineReactive(obj,key,val){
//這里用到了觀察者模式,它定義了一種一對多的關(guān)系屹徘,讓多個觀察者監(jiān)聽一個主題對象,這個主題對象的狀態(tài)發(fā)生改變時會通知所有觀察者對象衅金,觀察者對象就可以更新自己的狀態(tài)噪伊。
//實例化一個主題對象,對象中有空的觀察者列表
var dep = new Dep();
//將data的每一個屬性都設(shè)置為Vue對象的訪問器屬性氮唯,屬性名和data中相同
//所以每次修改Vue.data的時候鉴吹,都會調(diào)用下邊的get和set方法。然后會監(jiān)聽v-model的input事件惩琉,當(dāng)改變了input的值豆励,就相應(yīng)的改變Vue.data的數(shù)據(jù),然后觸發(fā)這里的set方法
Object.defineProperty(obj,key,{
get: function(){
//Dep.target指針指向watcher瞒渠,增加訂閱者watcher到主體對象Dep
if(Dep.target){
dep.addSub(Dep.target);
}
return val;
},
set: function(newVal){
if(newVal === val){
return
}
val = newVal;
//console.log(val);
//給訂閱者列表中的watchers發(fā)出通知
dep.notify();
}
});
}
//主題對象Dep構(gòu)造函數(shù)
function Dep(){
this.subs = [];
}
//Dep有兩個方法良蒸,增加訂閱者 和 發(fā)布消息
Dep.prototype = {
addSub: function(sub){
this.subs.push(sub);
},
notify: function(){
this.subs.forEach(function(sub){
sub.update();
});
}
}
通過訂閱發(fā)布消息的方式,監(jiān)聽每個數(shù)據(jù)的改變