vue数据双向绑定通过“数据劫持”+订阅发布模式实现。
1. Vue 的双向绑定(数据劫持)
vue.js 采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter、getter,在数据变动时发布消息给订阅者。
Vue 实现双向绑定的原理 就是利用了 Object.defineProperty() 方法重新定义了对象获取属性值get和设置属性值set 的操作实现的。
它接收三个参数,要操作的对象、要定义或者修改的对象属性、属性描述符。
const obj = {};
Object.defineProperty(obj, 'value', {
get: function() {
console.log('获取');
return val;
},
set: function(value) {
console.log('设置', value);
}
})
obj.value = 'value'; // 给obj设置value 属性,触发set方法
const val = obj.value; // 获取obj value属性,触发get方法
数据双向绑定,首先要对数据进行劫持监听,我们需要设置一个监听器 Observer,用来监听所有属性。
如果属性发生变化,就需要告诉订阅者Watcher看是否需要更新。 因为订阅者是有很多个,所以需要有一个消息订阅器Dep来专门收集这些订阅者,然后在监听器Observer和订阅者Watcher之间进行统一管理。
vue 如何实现
-
observer用来实现对每个vue的data定义的属性循环用Object.defineProperty()实现数据劫持,以便利用其中的setter和getter, 然后通知订阅者,订阅者会出发它的update方法,对视图进行更新。
-
在vue中v-model、v-name、{{}} 等都可以对数据进行显示, 也就是说,假如一个属性都通过这三个指令,那么每当这个属性改变的时候, 相应的这三个指令的HTML视图也必须改变,于是vue中就是每当有这样的可能用到双向绑定的指令,就在一个Dep中增加一个订阅者, 其订阅者知识更新自己的指令对应的数据,也就是v-model='name'和{{name}}有两个对应的订阅者,各自管理各自的地方。 每当属性的set方法触发,就循环更新Dep中的订阅者。
2. Angular 脏值检查
angular.js 是通过脏值检测的方式比对数据是否变更,来决定是否更新视图,最简单的方式就是通过setInterval() 定时轮询监测数据变动。 angular只有在指定的事件触发时进行脏值检测,大致如下:
-
DOM事件,譬如用户文本输入、点击按钮等。
-
XHR响应事件($http)
-
浏览器Location变更事件($location)
-
Timer 事件,(
interval)
-
执行
apply()
3. Backbone 发布者-订阅者
一般通过sub/pub的方式实现数据和视图的绑定监听,更新数据方式通常做法是 vm.set('property', value) 详细请看链接