前言
双向数据绑定是难点,也是面试时,提问极高的问题,接下来一起去看看
- 话述数据双向绑定
- 具体实现步骤
- 对涉及到的知识简单说明
面试话述
vue.js
是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()
来劫持各个属性的setter
,getter
,在数据变动时发布消息给订阅者,触发相应的监听回调来渲染视图
- 第一步: 需要
observer
对数据对象进行递归遍历,给所有属性都加上sette
r和getter
,当修改赋值时,触发set
方法,会被监听到。- 第二步:
compile
解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并给每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图- 第三步:
Watcher
订阅者是Observer
和Compile
之间通信的桥梁,主要做的事情是:
1、在自身实例化时往属性订阅器(dep
)里面添加自己
2、自身必须有一个update()
方法
3、待属性变动dep.notice()
通知时,能调用自身的update()
方法,并触发Compile
中绑定的回调,则功成身退。- 第四步:
MVVM
作为数据绑定的入口,整合Observer
、Compile
和Watcher
三者,通过Observer
来监听自己的model
数据变化,通过Compile
来解析编译模板指令,最终利用Watcher
搭起Observer
和Compile
之间的通信桥梁,达到数据变化 -> 视图更新;视图交互变化(input
) -> 数据model
变更的双向绑定效果。
Object.defineProperty()
的理解
Object.defineProperty()
方法是可以在对象上定义一个新属性,或者修改对象的现有属性,并返回此对象。
Object.defineProperty(obj, prop, descriptor)
obj
要定义属性的对象。
prop
要定义或修改的属性的名称。
descriptor
要定义或修改的属性描述符。(这个参数是一个对象)
var obj = { b: "123" }
console.log(obj)
Object.defineProperty(obj, "a", {
value: 37,//值
writable: true, //是否可以被修改
enumerable: true, //是否可以被枚举也就是是否可以遍历
configurable: true //是否可以被删除
});
// 控制台输出
for (let i in Object.keys(obj)) {
console.log(i)
}
obj.a = "36"
console.log(obj)
注: writable
enumerable
configurable
默认值都是false
,value
不给值的情况下是undefined
。
var Book = {}
var name = '';
Object.defineProperty(Book, 'name', {
set: function (value) { //value指当前给赋的值
name = value;
console.log('你取了一个书名叫做' + value);
},
get: function () {
return '《' + name + '》'
}
})
Book.name = 'vue'; // 你取了一个书名叫做vue权威指南
console.log(Book.name); // 《vue权威指南》