响应式原理

117 阅读3分钟

1、核心API-Object.defineProperty

1.1基本使用

image.png

image.png

2、如何实现响应式

2.1 demo准备

image.png

  • 上图例子中,通过observe这个入口函数对数据data进行监听,遍历data中的属性,将每个属性监听起来
  • 当我们修改data中的title属性时,触发set函数,进而调用updateCompon视图更新函数(关于这个函数暂时不做讲解,此例子只做一个视图更新标记)

2.2 复杂对象,深度监听

上述例子中只监听了一层data,假如data里面的属性又是一个对象会出现什么问题呢?我们应该如何处理呢?

image.png

  • 问题
    • 由上图例子发现,只有当我们修改info时才会触发视图更新,因为我们只监听了info属性
    • 而我们修改info.name时,并不会触发视图更新
  • 解决
    • 只需要在reative函数中对value值进行深度监听即可,我们来捋一下思路,首先入口函数observe(data),利用reactive函数监听data下面的每个属性,在reactive函数中对值(info)再次进行监听,observe函数中会判断info类型是否为对象,如果不是,就会终止,如果是则会继续遍历info下面的属性,如此在这两个函数中相互调用,实现深度监听

      image.png

  • 问题
    • 如果我们给某个属性设置新值,新值是一个对象,会不会进行监听呢?
  • 解决
    • 我们并没有对新设置的值进行observe操作,导致我们修改新值属性的时候不会触发更新,所以我们需要在set里面把新值也observe上,如下图

      image.png

2.3 监听数组

   由于Object.defineProperty无法监听数组,所以数组的监听需要进行额外的处理
  • 重新定义数组原型(如果对原型,原型链不熟悉的同学可以先去学习原型,原型链相关知识)
    • 思考:有哪些数组方法会改变原数组,push、unshift、pop、shift、splice、reverse、sort

    • Vue通过改写这些数组方法达到监听数组并更新视图的目的

      image.png

  • 为什么不直接通过Array.prototype.push = function(){}去重写数组原型方法呢?
    • 因为我们Vue是一个框架工具,这样操作会污染全局的Array原型

3、Object.defineProperty的一些缺点

3.1 监听需要递归监听到底

  • 原数据对象层级有多深,我们就要一次性递归循环到底,计算量大,如果一个页面数据层级过深,在初始化的过程中可能会出现卡死的现象

3.2 无法监听新增/删除属性

  • vue2中提供Vue.set Vue.delete函数去新增/删除对象的属性,原理后续我们分析Vue2中特殊函数时再进行讲解

3.3 无法监听数组

  • 通过重写数组原型方法解决

看完上面的分析,你对Vue的响应式原理有没有进一步的理解呢?我们先从易到难去理解分析,了解原理后再去学习源码会达到事半功倍的效果