vue3响应式(双向数据绑定)原理和vue2的区别
Vue 3 的响应式系统与 Vue 2 有显著的不同,Vue 3 使用了 Proxy 替代了 Vue 2 中的 Object.defineProperty,从而带来了更好的性能和更强大的功能。以下是 Vue 3 和 Vue 2 响应式原理的详细对比:
- Vue 2 的响应式原理
实现方式
Vue 2 使用 Object.defineProperty 来实现响应式。它会遍历对象的每个属性,将其转换为 getter 和 setter。
核心步骤:
初始化阶段:
-
遍历对象的每个属性,使用
Object.defineProperty将其转换为 getter 和 setter。 -
在 getter 中收集依赖(将当前 Watcher 添加到 Dep 中)。
-
在 setter 中触发更新(通知 Dep 中的所有 Watcher 更新)。
依赖收集:
-
每个属性都有一个对应的
Dep实例,用于存储依赖(Watcher)。 -
当属性被访问时,当前 Watcher 会被添加到 Dep 中。
派发更新:
- 当属性被修改时,会触发 setter,通知 Dep 中的所有 Watcher 更新。
// Vue 2 响应式实现(简化版)
function defineReactive(obj, key, val) {
const dep = new Dep(); // 每个属性都有一个 Dep 实例
Object.defineProperty(obj, key, {
get() {
if (Dep.target) {
dep.addSub(Dep.target); // 收集依赖
}
return val;
},
set(newVal) {
if (newVal === val) return;
val = newVal;
dep.notify(); // 派发更新
},
});
}
局限性:
无法检测新增属性:
- Vue 2 无法检测到对象属性的新增或删除(需要使用
Vue.set或Vue.delete)。
数组的限制:
- Vue 2 无法直接检测数组索引的变化(如
arr[0] = 1)和数组长度的变化(如arr.length = 0)。
性能问题:
- 初始化时需要递归遍历对象的每个属性,性能较差。
- Vue 3 的响应式原理
实现方式
Vue 3 使用 Proxy 来实现响应式。Proxy 是 ES6 的特性,可以拦截对象的操作(如读取、赋值、删除等)。
核心步骤:
初始化阶段:
-
使用
new Proxy()创建一个代理对象。 -
在代理对象中拦截属性的读取(get)和赋值(set)操作。
依赖收集:
- 在 get 拦截器中收集依赖(将当前 effect 添加到依赖集合中)。
派发更新:
- 在 set 拦截器中触发更新(通知依赖集合中的所有 effect 更新)。
// Vue 3 响应式实现(简化版)
function reactive(obj) {
return new Proxy(obj, {
get(target, key, receiver) {
track(target, key); // 收集依赖
return Reflect.get(target, key, receiver);
},
set(target, key, value, receiver) {
const result = Reflect.set(target, key, value, receiver);
trigger(target, key); // 派发更新
return result;
},
});
}
优势:
支持新增和删除属性:
- Proxy 可以拦截属性的新增和删除操作,无需额外 API。
更好的数组支持:
- Proxy 可以直接检测数组索引和长度的变化。
性能优化:
- Proxy 是惰性的,只有在访问属性时才会进行依赖收集,性能更好。
更强大的拦截能力:
- Proxy 可以拦截更多操作(如
in、delete、Object.keys等)。
- Vue 3 响应式系统的底层原理
Vue 3 的响应式系统基于 Effect 和 Dep 实现。
Effect
-
Effect 是一个副作用函数,当响应式数据变化时,Effect 会被重新执行。
-
Vue 3 使用
effect函数来创建 Effect。
Dep
- Dep 是一个依赖集合,用于存储所有依赖于某个属性的 Effect。
Track 和 Trigger
-
track:在 get 拦截器中调用,用于收集依赖。 -
trigger:在 set 拦截器中调用,用于触发更新。
- Vue 3 与 Vue 2 响应式系统的对比
| 特性 | Vue 2 | Vue 3 |
|---|---|---|
| 实现方式 | 使用 Object.defineProperty | 使用 Proxy |
| 新增属性检测 | 不支持(需使用 Vue.set) | 支持 |
| 数组支持 | 不支持直接检测索引和长度变化 | 支持 |
| 性能 | 初始化时需要递归遍历,性能较差 | 惰性依赖收集,性能更好 |
| 拦截能力 | 只能拦截属性的读取和赋值 | 可以拦截更多操作(如 in、delete) |
| API | 基于 Options API | 支持 Composition API 和 Options API |
总结
-
Vue 2 使用
Object.defineProperty实现响应式,存在一些局限性(如无法检测新增属性、数组变化等)。 -
Vue 3 使用
Proxy实现响应式,性能更好,功能更强大,支持更多操作。 -
Vue 3 的响应式系统基于
reactive、ref、computed、watch等 API,提供了更灵活的开发方式。
更多vue相关插件及后台管理模板可访问vue admin reference,代码详情请访问github