vue的响应式原理

之所以成为响应式,是因为vue可以监测到数据的变化,之后进行重新渲染。我们把这个过程叫做变化侦测。

首先聊聊变化侦测,分为两种类型推和拉。在react框架中使用的是拉的形式,当数据发生变化是,是不知道具体哪个状态变化了,需要暴力对比DOM节点,来找到需要重新渲染的节点。而Vue的变化侦测属于推的形式,当数据发生变化的时候,可以知道有数据发生了改变,而且可以知道那些数据发生了改变。但是推的形式追踪变化侦测,需要在每一个具体的DOM节点上添加依赖,会导致内存的消耗较大。所以vue从2.0开始,引入了虚拟DOM,不再是每一个具体的DOM结点有一个依赖,而是每个组件添加一个依赖,当数据变化的时候,定位到哪个组件发生了变化,之后在组件内进行虚拟DOM的对比。

我们再来看聊聊如何追踪变化,其实vue对于Object(对象类型)和Array(数组类型)的变化侦测的方式有一点不太一样。先说对于Object的侦测

Object的变化侦测

1.原理

vue2.0使用的侦测方法是Object.defineProperty()

Object可以通过Object.defineProperty将各个属性转换成getter/setter的形式来追踪,读取数据是触发getter,修改数据的时候触发setter。我们在getter中收集依赖,当setter被触发的时候,就去通知getter里面的依赖。依赖接受到通知后,会触发视图更新或回调函数等。

是不是理解起来有一点懵懂,没事我们细剖一下。

1.收集依赖?什么是依赖呢?是watcher!它相当于一个中介的角色,当数据发生变化时通知它,然后它再通知其他的地方。

        watcher的原理:watcher会把自己设置到全局唯一的一个指定位置处,然后读取数据,读取数据就会触发getter,getter就会从这个全局唯一的一个指定未知的地方读取到正在读取的watcher,并把它收集起来,当这个数据发生变化的时候,就可以去通知他数据变化了!

注意:getter/setter只能追踪一个数据是否被修改,无法追踪新增的属性或者删除的属性,需要用this.$set()或者this.$delete()

 Array的变化侦测

侦测的原理但是一样的,只不过侦测的方式有不同。

我们在改变数组数据时,通常使用数组的一些方法,如push,shift,splice等方法。我们只要能在调用push等操作的时候通知发生了改变就可以了。如果使用Object的getter和setter的形式就不可以了。但是JS并没有提供可以拦截原型方法的能力。所以用自定义方法覆盖原生的原型方法来解决。即拦截器。所以Array是在getter中收集依赖,在拦截器中触发依赖。

1.拦截器:拦截器就是一个和Array.prototype一样的一个对象,里面包含的属性一摸一样

2.拦截器如何覆盖Array的原型:在覆盖Array原型时,不可以直接覆盖,会污染到全局的Array。只需要拦截器覆盖那些响应式数组的原型就ok! 数据如果想转化成响应式那么一定会通过Observer,所以只需要在Observer中使用拦截器覆盖即可。

拦截器的源码:

export const arrMethods = Object.create(Array.prototye); // 继承Array.prototype
['push','pop','shift','unshift','splice','sort','reverse'].forEach((methods) =>{
    const original = arrayProto[method]
    Object.defineProperty(arrarMethods,method, {
        value: function mutator(..args) {
            return original.apply(this, args)
        },
        enumerable:false
        writable:true
        configurable:true
    }
}

当使用push方法的时候,调用的就是arrayMethods.push,即为mutator函数。

注意:对于Array的变化侦测是通过拦截原型的方式实现的,所以对于一些数组操作,vue时检测不到的,比如arr[1]=2,arr.length = 0.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值