this.cb = cb;
this.value = this.get();
}
Watcher.prototype.get = function() {
// 给 dep.target 置值,告诉 Observer 这是 Watcher 调用的 getter
dep.target = this;
// 调用 getter,触发相应响应
var value = this.data[this.exp];
// dep.target 还原
dep.target = null;
return value;
};
Watcher.prototype.update = function() {
this.cb();
};
function Observer(value) {
this.value = value;
this.walk(value);
}
Observer.prototype.walk = function(obj) {
var keys = Object.keys(obj);
for(var i = 0; i < keys.length; i++) {
// 给所有属性添加 getter、setter
defineReactive(obj, keys[i], obj[keys[i]]);
}
};
var dep = [];
dep.target = null;
function defineReactive(obj, key, val) {
// 有自定义的 property,则用自定义的 property
var property = Object.getOwnPropertyDescriptor(obj, key);
if(property && property.configurable === false) {
return;
}
var getter = property && property.get;
var setter = property && property.set;
// 递归的方式实现给属性的属性添加 getter、setter
var childOb = observe(val);
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function() {
var value = getter ? getter.call(obj) : val;
// 如果是 Watcher 监听的,就把 Watcher 对象压入 dep
if(dep.target) {
dep.push(dep.target);
}
return value;
},
set: function(newVal) {
var value = getter ? getter.call(obj) : val;
// set 值与原值相同,则不更新
if(newVal === value) {
return;
}
if(setter) {
setter.call(obj, newVal);
} else {
val = newVal;
}
// 给新赋值的属性值的属性添加 getter、setter
childOb = observe(newVal);
// 按序执行 dep 中元素的 update 方法
for(var i = 0; i < dep.length; i++) {
dep[i].update();
}
}
});
}
function observe(value) {
if(!value || typeof value !== 'object') {
return;
}
return new Observer(value);
}
var data = {a: 1};
new Observer(data);
new Watcher(data, 'a', function(){console.log('it works')});
data.a =12;
data.a =14;
上面基本实现了数据的监听,bug 肯定有不少,不过只是一个粗糙的 demo,只是想展示一个大概的流程,没有扣到非常细致。
Dep
上面几个例子,dep 是个全局的数组,但凡 new 一个 Watcher,dep 中就要多一个 Watcher 实例,这时候不管哪个 data 更新,所有的 Watcher 实例的 update 都会执行,这是不可接受的。
Dep 抽象出来,单独搞一个构造函数,不放在全局,就能解决了:










