1、核心API-Object.defineProperty
1.1基本使用
2、如何实现响应式
2.1 demo准备
- 上图例子中,通过observe这个入口函数对数据data进行监听,遍历data中的属性,将每个属性监听起来
- 当我们修改data中的title属性时,触发set函数,进而调用updateCompon视图更新函数(关于这个函数暂时不做讲解,此例子只做一个视图更新标记)
2.2 复杂对象,深度监听
上述例子中只监听了一层data,假如data里面的属性又是一个对象会出现什么问题呢?我们应该如何处理呢?
- 问题
- 由上图例子发现,只有当我们修改info时才会触发视图更新,因为我们只监听了info属性
- 而我们修改info.name时,并不会触发视图更新
- 解决
-
只需要在reative函数中对value值进行深度监听即可,我们来捋一下思路,首先入口函数observe(data),利用reactive函数监听data下面的每个属性,在reactive函数中对值(info)再次进行监听,observe函数中会判断info类型是否为对象,如果不是,就会终止,如果是则会继续遍历info下面的属性,如此在这两个函数中相互调用,实现深度监听
-
- 问题
- 如果我们给某个属性设置新值,新值是一个对象,会不会进行监听呢?
- 解决
-
我们并没有对新设置的值进行observe操作,导致我们修改新值属性的时候不会触发更新,所以我们需要在set里面把新值也observe上,如下图
-
2.3 监听数组
由于Object.defineProperty无法监听数组,所以数组的监听需要进行额外的处理
- 重新定义数组原型(如果对原型,原型链不熟悉的同学可以先去学习原型,原型链相关知识)
-
思考:有哪些数组方法会改变原数组,push、unshift、pop、shift、splice、reverse、sort
-
Vue通过改写这些数组方法达到监听数组并更新视图的目的
-
- 为什么不直接通过Array.prototype.push = function(){}去重写数组原型方法呢?
- 因为我们Vue是一个框架工具,这样操作会污染全局的Array原型
3、Object.defineProperty的一些缺点
3.1 监听需要递归监听到底
- 原数据对象层级有多深,我们就要一次性递归循环到底,计算量大,如果一个页面数据层级过深,在初始化的过程中可能会出现卡死的现象
3.2 无法监听新增/删除属性
- vue2中提供Vue.set Vue.delete函数去新增/删除对象的属性,原理后续我们分析Vue2中特殊函数时再进行讲解
3.3 无法监听数组
- 通过重写数组原型方法解决
看完上面的分析,你对Vue的响应式原理有没有进一步的理解呢?我们先从易到难去理解分析,了解原理后再去学习源码会达到事半功倍的效果