- 原理
view的变化能实时让model发生变化,而model的变化也能实时更新到view。
vue采用数据劫持&发布-订阅模式的方式,通过es5提供Object.defineProperty()方法来劫持(监控)各属性的getter、setter,并在数据(对象)发生变动时通知订阅者,触发相应的监听回调。并且,由于是在不同的数据上触发同步,可以精确的将变更发送给绑定的视图,而不是对所有的数据都执行一次检测。要实现vue中的双向数据绑定,大致可以划分三个模块:Observer、Compile、Water
Observe 数据监听器,负责对数据对象的所有属性进行监听(数据劫持),监听到数据发生变化后通知订阅者
Compiler 指令解析器,扫描模板,并对指令进行解析,然后绑定指定事件
Watcher 订阅者,关联Observer和Compile,能够订阅并收到属性变动的通知,执行指令绑定的相应操作,更新视图。Update()是它自身的一个方法,用于执行Compile中绑定的回调,更新视图。
模板渲染解析时watcher会对应绑定指令(一对一)
此时会通过调用订阅者watcher初始化(watcher中get()方法)去触发对应属性在发布者observer里(object.defineProperty)的getter, observer会判断是不是通过watcher初始化调用的(Dep.target实例化之后会清空),中有是才会通过dep类依赖收集。
observe通过depend通知Dep类收集(addDep方法,在watcher类中,会传入当前Dep实例调用自身)当前该订阅者(watcher)中的触发更新的方法,同时第一次初始化watcher.update()初始化视图。此后每次的数据更新都会通过observe中的setter去触发dep类中的回调update执行收集依赖的所有方法更新订阅者中的状态同时更新视图。
observe在处理对象和数组的时候,如果是数组,并且调用的方法会改变数组长度,则会重新增加索引之后更新数组,进行重新监听。(因为调用数组原生API可能多次触发getter setter 且索引不会变),如果是对象则通过对象的getter获取值和setter更新值。
- 版本比较
vue是基于依赖收集的双向绑定;
3.0之前的版本使用 Ojbect.defineProperty, 3.0新版本使用Proxy- 基于数据劫持/依赖收集的双向绑定的优点
a.不需要显示的调用,vue利用数据劫持+发布订阅,可以直接通知变化并且驱动视图
b.直接得到精确的变化数据,劫持了属性setter,当属性值改变我们可以精确的获取变化 的内容newVal,不需要额外的diff操作
2)object.defineProperty的缺点
a.不能监听数组;因为数组没有getter 和 setter ,因为数组长度不确定,如果太长性能负担太大。
b.只能监听属性,而不是整个对象;需要遍历属性;
c.只能监听属性变化,不能监听属性的删减
3)Proxy好处
a.可以监听数组;
b.监听整个对象不是属性
c.13种拦截方法,强大很多;
d.返回新对象而不是直接修改原对象,更符合immutable
4)proxy缺点
a兼容性不好,且无法用polyfill磨平。
- 基于数据劫持/依赖收集的双向绑定的优点