Vue实现双向数据绑定是采用数据劫持和发布者-订阅者模式。数据劫持是利用ES5的Object.defineProperty(obj,key,val)
方法来劫持每个属性的getter和setter,在数据变动时发布消息给订阅者,从而触发相应的回调来更新视图
总之就是,在创建Vue实例的时候给传入的data进行数据劫持,同时视图编译的时候,对于使用到data中数据的地方进行创建Watcher对象,然后在数据劫持的getter中添加到发布者对象中,当劫持到数据发生变化的时候,就通过发布订阅模式以回调函数的方式通知所有观察者操作DOM进行更新,从而实现数据的双向绑定。
/**
* 对Object.defineProperty()进行封装
*/
function defineReactive(obj, key, value) {
//递归 - 对象的属性仍是对象
observe(value);
//变化侦测
Object.defineProperty(obj, key, {
get() {
return value;
},
set(newVal) {
if (newVal !== value) {
updateView();
value = newVal;
observe(newVal)
}
}
})
}
/**
* 对一个对象所有属性的变化侦测
*/
function observe(target) {
//非对象,直接返回
if (typeof target !== 'object') {
return target;
}
//将每个属性转换为getter和setter形式
for (let key in target) {
defineReactive(target, key, target[key])
}
}
//模拟更新视图的方法
function updateView() {
console.log("更新视图");
}
通过直接调用observe侦测对象属性的变化
存在的问题
- 性能较差
- 对象上新增属性无法侦测
- 改变数组的length属性无法被侦测