这个问题现在都快被问烂掉了,相信大家或多或少都有自己的理解。
这里将从以下的角度来进行回答:
- 什么是数数据响应式?
- 为什么需要响应式?
- 它解决了什么问题?
- vue 2.x 中的响应式原理
- vue 3 中响应式的变化
在回答之前,可以看一看我之前写的数据响应式。
那么下面便开始回答吧~
什么是数据响应式?
所谓数据响应式,其实关键就在这个响应二字:能够检测数据的变化,当数据发生变化的时候,能够做出对应的响应,这就是数据响应式了。
为什么需要数据响应式?
我们都知道,一个框架、模式或者算法的出现,一定是为了解决工作中的痛点。
数据响应式也不例外,它的出现是为了解决前端开发中,开发者需要关注数据如何变化,又需要关注视图如何更新,从而导致开发难度高,维护成本高的问题。
它解决了什么问题?
做为胶水层,它解决了开发者需要兼顾视图与数据的问题。
数据响应式的出现,让用户在开发的时候,只需要关注业务逻辑,更细数据即可,而随后的 DOM 操作,视图更新则完全不必关心,这些都将有框架解决。
这极大地提升了开发效率,降低了开发难度。
vue 2.x 中的响应式原理
总所周知,vue 2.x 中实现数据响应式的核心 api 是
Object.defineProperty。
它的整个实现流程大致如下:
- 从
initState开始,处理 data 的方法为initData - 在
initData中调用observe做响应式处理 - 在
observe中会new Observer进入到响应式和核心部分 - 如果被处理的对象是数组,则先覆盖其数组原型的方法,然后
observe其元素 - 覆盖方法在
methodsToPatch,这是一个工厂,先执行原始方法,然后进行扩展,最核心的是调用了ob.dep.notify()通知视图更新 - 如果目标是纯对象,则在
walk中遍历 walk会调用defineReactive用于实现响应式- 如果被定义的目标是对象,则会递归查找到最深的子元素
defineReactive中的核心方法为Object.defineProperty- 在 get 中进行依赖收集
- 在 set 中通过
dep.notify()通知 Wather 更新视图
那么上面的流程,有什么局限性吗?
事实上是有的:
- 如果需要在对象中元素有变动,则需要使用额外的 api:
set/delete - 无法实现对 ES6 中新增数据类型的响应式,如
Set, Map
vue 3 中响应式的变化
关于这一点,尤大大多次的演讲都有提到,这里推荐大家去小破站搜一搜,相关视频非常多。
- 首先 vue 3 中实现响应式的核心 api 改为了 ES6 中新增的 Proxy
- 相比于递归遍历目标对象所有元素,Proxy 则是相当于在对象外层套一个壳子,这样性能要高能多(不用递归,不用开辟大量内存空间存储依赖关系)
- vue 3 中的响应式作为一个模块独立出来了,完全可以在不引入 vue 的情况下使用
结语
更佳阅读体验:016 - 说一说你对 vue 响应式的理解?