实现mvvm的双向绑定,是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。就必须要实现以下几点:
1、实现一个数据监听器Observer,能够对数据对象的所有属性进行监听,如有变动可拿到最新值并通知订阅者
2、实现一个指令解析器Compile,对每个元素节点的指令进行扫描和解析,根据指令模板替换数据,以及绑定相应的更新函数
3、实现一个Watcher,作为连接Observer和Compile的桥梁,能够订阅并收到每个属性变动的通知,执行指令绑定的相应回调函数,从而更新视图
4、mvvm入口函数,整合以上三者
那么实现数据双向绑定的核心就是利用为每一个属性都创建了订阅者的实例对象, 以便观察, getter函数里面返回一个value值,在setter函数中写入修改后的值并调用update方法更新视图的数据值, Configurable和Enumerable这两个特性描述符默认是true, 因此不用写
function defineReactive (obj, key, val) {
var dep = new Dep(); //这是一个构造函数 其原型是为属性添加订阅者
Object.defineProperty(obj, key, {
get: function() {
if(Dep.target) {
dep.addSub(Dep.target); //添加订阅者到Dep实例对象
}
return val; // 返回监听到的value值
},
set: function (newVal) {
if(newVal === val) return;
val = newVal; // 写入新的value值
dep.notify(); // 作为发布者发出通知 然后dep会迭代调用各自的update方法来更新视图
}
});
}
function observe(obj, vm) {
Object.keys(obj).forEach(function(key) {
defineReactive(vm, key, obj[key]);
});
}
https://www.jianshu.com/p/23180880d3aa
https://testerhome.com/articles/19818
(讲了哪个是订阅者)
按照我的理解:
watcher是是订阅者也是发布者,它受到observe传过来的数据的改变(订阅者),并且调用update函数把改变后的数值更新到视图上(发布者)
总结:
1.如果问数据的getter、setter属性是什么,就说getter是读取,setter是写入,剩下自由发挥
2.最上面那些答完,问,你没有提到Object.defineProperty,它在这里的作用呢
这时就说
observe监听到数据变化,它里面有个defineReactive,defineReactive里调用Object.defineProperty。
Object.defineProperty获取到新值,它的get属性里dep,这个dep就是订阅者(前面通过new Dep()创建),也是刚才说的watcher,
订阅者获取到observe传来的值(我是这么理解的)
set属性里比对如果值和之前发生改变,就调用update更新到视图上,没有就返回这个值(此时dep就充当发布者,也是watcher)