双向是指ViewModel中的data部分和View之间的双向关系。
正向:数据驱动页面
反向:页面更新数据
绑定是指自动化处理,data改变了view随之改变,反之也是。
不用像传统方式那样,通过onChange事件获取用户输入,然后再通过改变innerHtml修改显示。
双向绑定都是依赖ES5中一个重要的API,Object.defineProperty
数据劫持结合发布-订阅者的方式;通过Object.defineProperty来劫持各个属性的getter\setter来监听属性变化,实现Observer监听
- 监听者 (Observer): 有一个监听者(Observer),监听 data发生的变化, (通过Object.defineProperty 的get 属性重新遍历,修改 get 和 set 操作,还会有一个递归的操作,如果操作的是一个子对象,会对这个子对象重新进行递归遍历一遍保证所有的key值都是有 observer 对象的。)
- 观察者列表 (Dep): 数据的变化会触发 Object.defineProperty 对象的set 属性,set 会执行对观察者列表的触发,通知观察者列表(Dep)
- 列表会有一个更新函数,通知了它们,它们会自动调用 updated 更新函数,也就是 Dep 调用了 回调,这个 回调是 观察者 (watcher)给的
- 观察者(watcher): watcher 拿到更新后的数据就可以更新到 view了
- 观察者列表的updated 是怎么传进去的,是通过 watcher 的订阅,watcher 往观察者列表添加新的内容(监听完后会有一步实例化 watcher 对象,想对A 操作,observer 完后会手动调用一下watcher,实例化watcher,watcher 会调用 get,检测watcher全局变量是否有值,有值的话会调用 deep.target,把内容往 Dep添加)
Object.defineProperty 与 Reflect.defineProperty 的区别:
Object.defineProperty是 ES5 的用法,返回的是一个对象
Reflect.defineProperty是ES6 的用法,返回的是一个布尔值
Object.defineProperty缺点:
深度监听,需要递归到底,一次性计算量大
无法监听新增/删除属性(所以需要 vue.set vue.delete 实现新增/删除属性)
无法监听原生数组,需要特殊处理