简述Vue的响应式原理

1,930 阅读3分钟

Vue是一个响应式的框架,响应式是指:数据模型仅仅是普通的 JavaScript 对象。而当你修改它们时,视图会进行更新。

那么Vue是怎么做到响应式的呢?

可以从两个方面来讨论:Object和Array。

Object

受现代JavaScript 的限制 (以及废弃 Object.observe),Vue不能检测到对象属性的添加或删除。所以Vue通过Object.defineProperty来处理数据,把属性变成getter/setter属性,因为Object.defineProperty是ES5的一个不能shim的特性,所以不支持IE8及以下。

1、如何追踪变化:

Vue追踪变化,是把对象用Object.defineProperty把遍历对象,使用Observer类把对象的每个属性改写成用getter/setter来设置和获取值的改变。这样Vue就可以通过触发getter和setter方法来处理数据,就可以获取数据的改变。

2、依赖的收集和触发

2.1 什么是依赖?

用到该属性的地方,就是依赖,但是Vue封装了一个watch类来当作依赖,这个watch类能通知使用该属性的所有依赖。所以Vue收集的依赖就是收集watch类。

2.2 如何收集依赖?

Vue在getter方法里收集依赖,Vue把依赖解耦成一个专门的Dep类,来处理收集和触发依赖。在使用该数据的时候,便把依赖收集到Dep里。

2.3 如何触发依赖

在数据发生改变的setter函数里触发依赖,Vue声明的watch类,当数据发生了改变的时候,Vue通知watch数据发生变化,让watch自己去通知依赖发生改变。

3、Object的问题

Vue使用Object.defineProperty的getter和setter来把对象变成响应式的对象,但是也因为这个,Vue能监听到该Object属性值的变化,却监听不到Object增加和删除属性。所以Vue提供了两个API:vm.set和vm.delete来处理增加属性和删除属性。

Array

Vue对象是通过getter/setter 来监听到对象的数据变化从而让对象变成响应式的。但是在数组里,有一些原型上的方法比如push,pop,shift…等,并不会触发getter/setter 就可以改变数组的值,Vue在这个时候,就没有办法进行监听从而触发视图的改变了。

1、如何追踪变化

Vue重写了push,pop,shift,unshift,reverse,sort,splice这7个会改变Array本身的原型方法,并通过一个拦截器,把需要响应的数组,覆盖他们的原型方法。value.proto=arraysMethods.如果不支持__proto__的属性,那么Vue会暴力的把这些方法放到这些数组本身。

2、依赖的收集和触发

2.1 在哪儿收集和触发依赖

Vue对数组和对象都一样,都是在getter里收集依赖,在setter里触发依赖。

2.2 依赖放在哪儿

对象的依赖放在Dep类里,而数组的依赖放在Observer实例的Dep里。目的是为了在getter和Array的拦截器都里能访问到Observer的实例。

Vue改写了上面Object的Observer的类,给每个属性加一个__ob__属性,通过对该属性的来判断是否响应式,且是否发生改变,从而触发依赖。