Vue2 响应式理解

112 阅读3分钟

响应式原理

什么是响应式

  • 顾名思义,监测变化,做出响应。

监测变化

  • Object是JavaScript中的一种数据类型,是引用类型
  • 对于Object属性的变化,JavaScript提供了Object.defineProperty和Proxy来监测
  • Vue2的响应式就是通过Object.defineProperty来监测的
  • Object.defineProperty( obj, prop, descriptor )
    • 这个方法的具体用法参考MDN
    • 该方法每次只能观测对象的其中一个prop
    • 该方法只能观测对象已有的prop
  • Vue2是如何实现data配置项的响应式的
    • 获取到data,有可能是对象或者返回对象的函数
    • 拿到最终的data对象,然后遍历对象的每个prop,调用Object.defineProperty去监测变化

做出响应

  • 简单的两个问题:对于监测到的变化,谁要去处理,怎么处理
  • 对于Vue2框架本身,监测到data的属性变化后,所有用到该属性的模板都要重新渲染。
  • 即Vue2框架自身去处理,调用渲染函数重新渲染页面来处理

完善响应式

  • 到现在为止,对于data对象属性的响应式还有几点不足

    1. 目前实现的只是对于data对象本身属性的侦测,且属性必须是基本类型,而不能是引用类型
    2. 把上述过程封装为一个函数,则该函数的功能就是实现对一个对象的所有基本属性的侦测和响应
  • 针对以上问题依次解决

    1. 深层响应:对于属性也为对象时,要深层监视变化,则可以通过嵌套调用封装的监视变化的函数
    2. 数组属性:如果属性是数组类型,由于Array本身没有提供方法来监测元素的变化,因此Vue2通过代理模式,将原有的操作数组元素的方法重写,这样在重写的方法中就能在其每次被调用时监测变化。

注意点

  1. 目前Vue2的响应式只支持data对象中属性类型为基本类型,对象,数组
  2. 对于数组也必须使用七个操作数组元素的方法,而不能通过下标来操作
  3. Object.defineProperty只能观察data对象中显式存在的属性,新增的属性,没有经过defineProperty,没有响应式
  4. 删除的属性,由于在删除前其已经存在,即已经在defineProperty监测中了,而delete动作不会被捕获到,值没有发生变化,只是不存在了为undefined

扩展

  • 如果把对data对象的响应式的实现过程封装一遍,那就可以对任意的对象进行同等功能的监测
  • 比如$watch就是简单封装,进行了部分改动,实现了对任意对象的监测
  • 与Vue框架本身的响应式不同的是,$watch让我们可以自定义监测变化后要做出的响应,而不是Vue自动重渲染
  • 对已经监测过的对象新增和删除属性实现响应式,
    • 与数组的变化侦测思想一致,通过代理模式
    • 创建setset,delete方法,在方法内去调用原生的delete,和点语法新增。
    • 由于用户调用的是我们创建的set,set, delete方法,因此我们能监测到这个变化的动作,当变化后,我们可以手动调用defineProperty来对新增的属性进行监测
    • delete,与delete,与set同理