从 Vue3 回望 Vue2
- [02 | 响应式的内核革命:从 defineProperty 到 Proxy](#02 | 响应式的内核革命:从 defineProperty 到 Proxy)
-
- [一、Vue2 的响应式系统:defineProperty 的极限边界](#一、Vue2 的响应式系统:defineProperty 的极限边界)
-
- [1.1 基础实现机制](#1.1 基础实现机制)
- [1.2 Vue2 的典型痛点](#1.2 Vue2 的典型痛点)
-
- [❌ 无法侦测新增属性](#❌ 无法侦测新增属性)
- [❌ 无法拦截数组索引](#❌ 无法拦截数组索引)
- [❌ 深层递归导致性能问题](#❌ 深层递归导致性能问题)
- [❌ 对象粒度低、不可统一代理](#❌ 对象粒度低、不可统一代理)
- [二、Vue3 的响应式新核心:Proxy 重构一切](#二、Vue3 的响应式新核心:Proxy 重构一切)
-
- [2.1 Proxy 简介](#2.1 Proxy 简介)
- [2.2 真实场景对比:Vue2 无法监听 → Vue3 自动响应](#2.2 真实场景对比:Vue2 无法监听 → Vue3 自动响应)
-
- [👇 Vue2 示例:无法监听新增属性](#👇 Vue2 示例:无法监听新增属性)
- [✅ Vue3 示例:Proxy 自动监听新增](#✅ Vue3 示例:Proxy 自动监听新增)
- [👇 Vue2 示例:数组索引变更无效](#👇 Vue2 示例:数组索引变更无效)
- [✅ Vue3 示例:数组索引变更支持](#✅ Vue3 示例:数组索引变更支持)
- [2.3 Proxy 带来的全面提升](#2.3 Proxy 带来的全面提升)
- 三、组合式响应式体系:不仅是技术重构,更是思维革新
-
- [3.1 `reactive`、`ref`、`readonly`:响应式三件套](#3.1
reactive
、ref
、readonly
:响应式三件套) - [3.2 响应式陷阱需注意](#3.2 响应式陷阱需注意)
- [3.1 `reactive`、`ref`、`readonly`:响应式三件套](#3.1
- 四、生态协同与开发体验的全面升级
-
- [4.1 状态管理:从 Vuex 到 Pinia 的演进](#4.1 状态管理:从 Vuex 到 Pinia 的演进)
- [4.2 VueUse 等工具库深度绑定响应式 API](#4.2 VueUse 等工具库深度绑定响应式 API)
- 五、小结:从响应式实现到响应式哲学的跃迁
02 | 响应式的内核革命:从 defineProperty 到 Proxy
框架不是重做,而是进化
Vue 最吸引人的特性之一,就是其"开箱即用"的响应式系统。在 Vue2 中,它以 Object.defineProperty
为核心,通过劫持每一个属性,构建起响应式世界;而到了 Vue3,框架不再沿用旧机制,而是以 ES6 的 Proxy
为基础进行了彻底重构。
这并不是推倒重来,而是一次对响应式范式的重塑升级。
本文将带你从 Vue3 的视角出发,回望 Vue2 的响应式实现,解构其技术局限,深入理解 Proxy 带来的革新,并探讨其对开发实践与生态系统的深远影响。
一、Vue2 的响应式系统:defineProperty 的极限边界
1.1 基础实现机制
Vue2 通过递归遍历对象的每一个属性,使用 Object.defineProperty()
将其转为响应式:
js
function defineReactive(obj, key, val) {
Object.defineProperty(obj, key, {
get() {
// 依赖收集
return val
},
set(newVal) {
if (newVal !== val) {
// 派发更新
val = newVal
}
}
});
}
这套机制支撑了 Vue2 的大部分响应式特性,但在使用过程中,我们会频繁遇到各种"不响应"或"响应丢失"的问题。
1.2 Vue2 的典型痛点
❌ 无法侦测新增属性
js
vm.obj.newProp = 123; // 不会触发视图更新
必须使用 Vue.set(vm.obj, 'newProp', 123)
才能保持响应式。但这种 API 并不直觉,尤其对新手极不友好。
❌ 无法拦截数组索引
js
vm.arr[1] = 'new'; // 不会触发视图更新
Vue2 对数组只能拦截变异方法(如 push
、splice
),索引赋值和长度修改无能为力。
❌ 深层递归导致性能问题
初始化响应式对象时,Vue2 会递归所有嵌套属性,导致深层数据结构在初始化时非常耗性能,甚至引起页面卡顿。
❌ 对象粒度低、不可统一代理
每个属性都要手动定义 getter/setter,不仅效率低,也无法统一处理对象行为,比如删除属性、遍历属性等。
正是这些机制级别的限制,让 Vue2 在面对大型复杂状态管理时显得力不从心。要解决这些问题,需要一次范式层面的突破 ------ Vue3 选择了 Proxy。
二、Vue3 的响应式新核心:Proxy 重构一切
2.1 Proxy 简介
Proxy
是 ES6 引入的新特性,允许我们创建一个对象的代理,拦截并定义对该对象的所有基本操作,如读取、赋值、删除、遍历等。
Vue3 使用 Proxy 构建响应式代理对象,核心逻辑如下:
js
const handler = {
get(target, key, receiver) {
// 依赖收集
return Reflect.get(target, key, receiver)
},
set(target, key, value, receiver) {
// 派发更新
return Reflect.set(target, key, value, receiver)
}
}
const state = new Proxy(target, handler)
相比 Vue2 的属性级别劫持,Vue3 是对象级别代理,更加灵活与全面。
2.2 真实场景对比:Vue2 无法监听 → Vue3 自动响应
👇 Vue2 示例:无法监听新增属性
js
data() {
return {
user: { name: 'Alice' }
}
}
mounted() {
this.user.age = 18; // ❌ 不响应
}
✅ Vue3 示例:Proxy 自动监听新增
js
setup() {
const state = reactive({ user: { name: 'Alice' } })
state.user.age = 18; // ✅ 响应式自动生效
}
👇 Vue2 示例:数组索引变更无效
js
this.items[1] = 'updated'; // ❌ 视图不会更新
✅ Vue3 示例:数组索引变更支持
js
state.items[1] = 'updated'; // ✅ 触发响应式更新
2.3 Proxy 带来的全面提升
特性 | Vue2(defineProperty) | Vue3(Proxy) |
---|---|---|
新增/删除属性监听 | ❌ 需要 Vue.set / Vue.delete |
✅ 自动追踪 |
数组索引修改响应 | ❌ 不支持 | ✅ 完全支持 |
初始化性能 | ❌ 递归遍历,慢 | ✅ 懒代理,按需处理 |
嵌套响应 | ❌ 手动递归 | ✅ 自动深层追踪 |
Map/Set 等对象支持 | ❌ 无法处理 | ✅ 完全代理 |
代码简洁性 | 一般,侵入式强 | 极简、天然响应式 |
三、组合式响应式体系:不仅是技术重构,更是思维革新
3.1 reactive
、ref
、readonly
:响应式三件套
Vue3 通过多个 API 构建灵活多样的响应式系统:
js
import { reactive, ref, readonly, shallowReactive } from 'vue'
const state = reactive({ count: 0 })
const num = ref(100)
const readonlyState = readonly(state)
const shallow = shallowReactive({ nested: { a: 1 } })
reactive
:深层对象响应式代理ref
:原始值响应式封装readonly
:构建只读响应式对象,适合保护 props 或共享状态shallowReactive
:仅处理第一层属性,适合性能优化场景
3.2 响应式陷阱需注意
- ❗ 不能解构
reactive
对象,否则失去响应性 - ❗
reactive
不能作用于基本类型(需使用ref
) - ❗ 多层响应式嵌套对象更新时可能触发较多依赖,需配合
watchEffect
优化
四、生态协同与开发体验的全面升级
4.1 状态管理:从 Vuex 到 Pinia 的演进
Pinia 借助 Proxy + 组合式 API,取代 Vuex 成为官方推荐状态管理方案:
ts
import { defineStore } from 'pinia'
export const useCounter = defineStore('counter', {
state: () => ({ count: 0 }),
actions: {
increment() {
this.count++
}
}
})
响应式特性完全基于 Vue3 的 Proxy 系统,无需额外依赖。
4.2 VueUse 等工具库深度绑定响应式 API
如 useMouse()
、useDark()
等组合函数,底层大量使用 ref
与 reactive
,依赖 Proxy 实现高性能、无副作用的自动状态跟踪。
五、小结:从响应式实现到响应式哲学的跃迁
Vue3 的 Proxy 并不仅仅解决了 Vue2 遇到的"局部问题",更构建出一套完整的响应式范式 ,其优势不仅体现在功能覆盖上,更在于设计的简洁性、一致性与未来可扩展性。
这是一场范式的升级:
Vue2 教我们如何"让状态变得响应式";Vue3 教我们如何"用响应式编程状态"。
响应式不再是技术细节,而成为 Vue3 核心的哲学支柱。