vue数据双向绑定是通过数据劫持结合发布者-订阅者模式的方式来实现的,我们可以先来看一下通过控制台输出一个定义在vue初始化数据上的对象是什么。
var vm = new Vue({
data: {
obj: {
a: 1
}
},
created: function () {
console.log(this.obj);
}
});
结果:
我们可以看到属性a有两个相对应的get和set方法,为什么会多出这两个方法呢?因为vue是通过Object.defineProperty()来实现数据劫持的。
Object.defineProperty( )是用来做什么的?它可以来控制一个对象属性的一些特有操作,比如读写权、是否可以枚举,这里我们主要先来研究下它对应的两个描述属性get和set,如果还不熟悉其用法,请点击这里查看更多用法。
在平常,我们很容易就可以打印出一个对象的属性数据:
var Book = {
name: 'JavaScript设计模式'
};
console.log(Book.name); // JavaScript设计模式
如果想要在执行console.log(Book.name)的同时,直接给书名加上书名号,那要怎么处理呢?或者说要通过什么监听对象 Book 的属性值。这时候Object.defineProperty( )就派上用场了,代码如下:
var Book = {}
var name = '';
Object.defineProperty(Book, 'name', {
set: function (value) {
name = value;
console.log('书名叫' + value);
},
get: function () {
return '《' + name + '》'
}
})
Book.name = 'JavaScript设计模式'; // 书名叫JavaScript设计模式
console.log(Book.name); // 《JavaScript设计模式》
我们通过Object.defineProperty( )设置了对象Book的name属性,对其get和set进行重写操作,顾名思义,get就是在读取name属性这个值触发的函数,set就是在设置name属性这个值触发的函数,所以当执行 Book.name = ‘JavaScript设计模式’ 这个语句时,控制台会打印出 “书名叫JavaScript设计模式”,紧接着,当读取这个属性时,就会输出 “《JavaScript设计模式》”,因为我们在get函数里面对该值做了加工了。如果这个时候我们执行下下面的语句,控制台会输出什么?
console.log(Book);
没错,vue就是通过这种方法来进行数据劫持的。