1.原理
View的变化能实时让Model发生变化,而Model的变化也能实时更新到View。
Vue采用数据挟持&发布-订阅模式的方式,通过ES5提供的Object.defineProperty()方法挟持(监听)各属性的getter、setter,并在数据发生变化时通知所有的订阅者(使用该属性的组件对象),触发相应的监听回调。要实现Vuex中的双向数据绑定,大致可以划分三个模块:Observer、Compiler、Watcher,如图:
- Observer 数据监听器,负责对数据对象的所有属性进行监听(数据挟持),监听到数据变化后通知订阅者。
- Compiler 指令解析器,负责扫描模版,并对模版上的指令进行解析,然后绑定指令事件。
- Watcher 订阅者,关联Observer和Compiler。能够订阅并收到属性变更的通知,执行指令绑定的相应操作,更新视图。内部实现了update()方法,用于执行Compiler中绑定的回调,更新视图。
模版解析时Watcher会对应绑定指令(一对一),此时会通过调用订阅者Watcher初始化(Watcher中的get())去触发对应属性在发布者Observer里(Object.defineProperty)的getter,Observer会判断是不是通过Watcher初始化调用的,如果是才会通过Dep类进行依赖收集。同时第一次调用Watcher.update()来初始化视图。此后每次的数据更新都会通过Observer中的setter去触发通过Dep类收集的依赖中的update回调,更新订阅者中的状态同时更新视图。
Observer在处理对象和数组的时候,如果是数组,并且调用的方法会改变数组长度,则会重新增加索引之后更新数组,进行重新监听(因为调用数组原生api会多次触发getter、setter且索引不会变)。如果是对象则通过对象的getter获取值和setter更新值。
2.版本比较
Vue是基于依赖手机的双向绑定;
3.0之前的版本使用Object.defineProperty,3.0新版使用Proxy。
1)基于数据挟持/依赖收集的双向绑定优点
- 不需要显示的调用,Vue利用数据挟持+发布订阅,可以直接通知变化并且驱动视图。
- 直接得到精确的变化数据,挟持了属性setter,当属性值改变我们可以精确的获取变化的内容,不需要额外的diff操作。
2)Object.defineProperty的缺点
- 不能监听数组,因为如果数组的长度不确定,监听会频繁触发其getter、setter,性能负担太大(Proxy同样存在该问题)。
- 只能监听属性,而不是整个对象,需要遍历属性。
- 只能监听属性变化,不能监听属性的删减。
3)Proxy的优点
- 监听整个对象不用遍历属性。
- 13种拦截方法,强大很多。
- 返回新对象而不是直接修改原对象,更符合immutable。
4)Prpxy的缺点
- 兼容性不好,且无法用polyfill磨平。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END