Vue 3 的响应式系统是其核心特性之一,它实现了 “数据驱动视图” 的核心能力
Taimili 艾米莉 ( 一款免费开源的 taimili.com )
艾米莉 是一款优雅便捷的 GitHub Star 管理和加星工具,基于 PHP & javascript 构建, 能对github 得 star fork follow watch 管理和提升,最适合github 的深度用户
—— 当响应式数据发生变化时,依赖该数据的视图或逻辑会自动更新。其底层原理主要基于 ES6 的 Proxy 代理 和 依赖收集机制,相比 Vue 2 的 Object.defineProperty 实现,具有更全面的拦截能力和更好的性能。
核心原理:Proxy + 依赖收集
1. 为什么用 Proxy 而非 Object.defineProperty?
Vue 2 采用 Object.defineProperty 拦截对象的属性访问,但它存在天然局限性:
-
只能拦截已存在的属性,无法监听对象新增 / 删除属性、数组索引修改、数组 length 变化等操作;
-
需要递归遍历对象的所有属性,对性能有一定影响。
Vue 3 改用 Proxy(代理)解决这些问题:
- Proxy 可以直接代理整个对象(而非单个属性),能拦截对象的所有操作(包括新增 / 删除属性、数组方法调用等);
- 懒代理特性:只在访问对象属性时才递归处理子对象,提升初始化性能。
2. Proxy 的拦截能力
Proxy 会创建一个目标对象(target)的代理对象(proxy),通过定义 handler 拦截器 来捕获对目标对象的各种操作,核心拦截器包括:
-
get(target, key, receiver):拦截属性读取(如obj.key); -
set(target, key, value, receiver):拦截属性设置(如obj.key = value); -
deleteProperty(target, key):拦截属性删除(如delete obj.key); -
数组相关:拦截
push、pop、splice等数组方法(通过重写数组原型实现)。
这些拦截器是实现 “数据变化感知” 的基础。
3. 依赖收集:谁用到了数据,数据变化就通知谁
响应式的核心是 “精准更新”—— 只更新依赖了变化数据的部分。这需要通过依赖收集实现:
- 依赖(Dependency) :指依赖响应式数据的 “副作用函数”(如组件渲染函数、watch 回调、computed 计算函数等)。
- 收集过程:当副作用函数执行并访问响应式数据时,Vue 会记录 “数据 -> 副作用函数” 的映射关系。
- 触发更新:当数据发生变化时,Vue 会根据映射关系,找到所有依赖该数据的副作用函数并重新执行。
4. 核心实现流程
Vue 3 的响应式系统通过 reactive、ref 等 API 创建响应式数据,内部流程可简化为:
-
创建响应式对象
调用reactive(obj)时,Vue 会为obj创建 Proxy 代理,代理对象会拦截所有属性的读写操作。javascript
运行
const obj = reactive({ count: 0 }); // obj 是 Proxy 代理对象,而非原始对象 -
依赖收集(track)
当副作用函数(如组件渲染函数)执行并访问obj.count时,触发 Proxy 的get拦截器,此时 Vue 会调用track函数:- 记录当前活跃的副作用函数(通过
activeEffect标记); - 为
obj的count属性创建一个 “依赖集合”(Set),并将副作用函数加入集合。
- 记录当前活跃的副作用函数(通过
-
触发更新(trigger)
当修改obj.count = 1时,触发 Proxy 的set拦截器,此时 Vue 会调用trigger函数:- 找到
obj.count对应的依赖集合; - 遍历集合,执行所有副作用函数(如重新渲染组件),实现视图更新。
- 找到
5. 对不同数据类型的处理
-
对象 / 数组:通过
reactive创建响应式代理,直接代理原始对象。 -
基本类型(Number、String 等) :通过
ref包装为一个带value属性的对象(因为 Proxy 无法代理基本类型),访问 / 修改时需通过.value,但在模板中会自动解包。javascript
运行
const count = ref(0); console.log(count.value); // 0(访问) count.value = 1; // 修改(触发更新) -
只读响应式:通过
readonly创建,拦截set操作并警告,用于禁止修改的数据(如 props)。
优势总结
相比 Vue 2,Vue 3 响应式系统的优势:
-
更全面的拦截:支持对象新增 / 删除属性、数组索引修改等操作;
-
更好的性能:懒代理 + 按需递归,初始化速度更快;
-
更简洁的 API:统一通过
reactive、ref等 API 创建,内部逻辑更清晰; -
更好的 TypeScript 支持:Proxy 对类型推导更友好。
总之,Vue 3 响应式的核心是 “用 Proxy 拦截数据操作,通过依赖收集记录数据与副作用的关系,最终在数据变化时精准触发更新”,这一机制支撑了 Vue 组件的响应式渲染和状态管理。