vue三要素
- 响应式:如何监听数据变化(双向数据绑定)
- 模版引擎:如何解析模板
- 渲染:vue如何将监听到的数据变化和解析后的html进行渲染
实现双向数据绑定有挺多种方法:knockoutJS基于观察者模式的双向数据绑定,Ember基于数据模型的双向数据绑定,而angularjs是基于脏值检查。Vue则是基于数据劫持。
基于数据劫持的优点
- 无需显式调用。vue利用发布者订阅者模式+数据劫持,可以直接通知变化并更新视图。比如data.name = '渣渣辉‘;后直接触发变更,而比如Angular的脏值检测则需要显式调用markForCheck
- 可精确得知变化数据:劫持了属性setter之后,当属性值改变,我们可以精确知道变化的内容newVal,因此在这一部分不需要多余的diff操作。否则我们只知道数据变化了,但是不知道具体哪些数据发生变化,所以需要大量的diff来找出变化值。这是额外的性能损耗。
基于数据劫持双向绑定的实现思路
常见的基于数据绑定有两种实现,一个是利用Object.defineProperty,一种是ES6中新增的proxy。
- 利用proxy或者object.defineProperty等方法对对象/属性的“劫持”,在属性变化之后通知订阅者。
- 解析器compile解析模板中的Directive(指令),收集指令所依赖的方法和数据,等待数据变化然后进行渲染。替换数据,绑定函数,渲染视图
- watcher属于observer和compile桥梁,它将接收到的Observer产生的数据变化,并根据compile提供的指令进行视图渲染,使得数据变化促使视图变化。
基于Object.defineProperty双向数据绑定的特点
object.defineProperty的缺点:
- 无法监听数组的变化,vue的实现是给数组添加hack,为数组的原生几个能改变数组的方法,pop 、push、shift、unshift、splice、sort、reverse,添加响应。
- 只能劫持对象的属性,因此我们需要对每个对象的属性进行遍历。如果属性值也是一个对象,则需要进行深度遍历。显然如果能够直接劫持整个对象更好。
proxy实现双向数据的特点
proxy是es6中的新语法,在目标对象之前架设一层“拦截”,外界对该对象的访问都需要经过这层拦截。因此可以提供一种机制:对外界的访问进行过滤和更改