Vue中数据响应式原理---对象的变化侦测

什么是变化侦测?

Vue.js会自动通过状态生成DOM,并将其输出到页面上显示出来,这个过程叫做渲染。
那么,在运行时应用内部的状态会不断发生变化,此时需要不停的重新渲染,如何确定状态中发生了什么变化?
这里就用到了 “变化侦测”,它就是用来监听内部数据状态变化的。

变化侦测的分类?

变化侦测分为两种类型,一种是 “推”(push) ,一种是 “拉”(pull)。
目前我们的前端主流框架中,Angular 和 React 中的变化侦测都属于 “拉” 的模式,也就是说,当状态发生变化时,它们并不知道哪个状态变了,只知道有可能变了,然后会发出一个信号告诉框架,框架接收到信号后,会进行一个暴力比对来找出那些DOM节点需要重新渲染。

这在Angular中是脏检查的流程,在React中使用的是虚拟DOM。

在Vue.js中的变化侦测属于 “推” 的过程,当状态发生变化时,Vue.js立刻就知道了,而且在一定程度上知道那些状态变化了。因此,在Vue.js中可以进行更细粒度的更新。

如何侦测一个对象的变化?

在JS中,如果想侦测一个对象的变化,有两种办法:

  • 1.使用 Object.defineProperty
  • 2.使用 ES6 的 Proxy

注: 由于ES6在浏览器中的支持度并不理想,在Vue2.0源码中,还是使用了Object.defineProperty来实现的,但使用Object.defineProperty来侦测变化会有很多缺陷,比如:

  • 没办法直接侦测数组的变化
  • 对于多层的对象,需要使用递归进行侦测,多层递归会影响性能
  • 没办法对新增、删除的属性进行侦测

所以,在已发布的测试版Vue3.0的源码里,作者使用Proxy重写了这部分的代码。

这里主要说说Vue2.0源码中的数据侦测的实现,同时也是对学习过程中的一个知识梳理。Proxy的方式实现数据侦测待Vue3.0源码正式版发布后,再和小伙伴们做讨论。

=> 使用Object.defineProperty来实现数据追踪?

代码如下:

// 定义一个响应式数据,在此函数中追踪变化
function defineReactive(data, key, val) {
   
  Object.defineProperty(data, key, {
   
    enumerable: true,
    configurable: true,
    get: function() {
   
      return val
    },
    set: function(newVal) {
   
      if(val === newVal) {
   
        return
      }
      val = newVal
    }
  })
}

通过上方defineReactive函数的封装,就能实现每当从data的key中读取数据时,get函数被触发,每当往data的key中设置数据时,set函数被触发。

如何收集依赖?

我们之所以要观察数据,目的是当数据发生变化时,可以通知曾经使用了该数据的地方,进行更新、渲染,所以我们要先收集依赖
收集依赖: 即把用到数据的地方收集起来,等属性发生变化时,把之前收集好的依赖循环触发一遍就好了。

在Vue2.0中,模板使用数据等同于组件使用数据,所以当数据发生变化时,会将通知发送到组件,然后组件内部再通过虚拟DOM重新渲染。

总结下来就是:在getter中收集依赖,在setter中触发依赖。

=> 依赖是什么?

数据变化时,曾经使用了该数据的地方有很多,而且类型可能还不一样,既有可能是模板,也有可能是用户写的一个watch。所以,我们需要抽象出一个能集中处理这些情况的类。
然后,在收集依赖阶段,只收集这个封装好的类的实例进来,通知也只通知它一个,它再负责通知其他地方,这个抽象的东西(类),就叫做 Watcher .

=> 依赖收集在哪里?

现在已经明确了,在getter中收集依赖,假设依赖是一个函数,保存在window.target上,我们就可以把依赖收集的代码封装成一个Dep类,帮助我们管理依赖:

// 为了减少耦合,把收集依赖的代码封装成一个dep类,专门帮助我们管理依赖
export default class Dep {
   
  constructo
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值