一、响应式系统
响应式是 Vue 自动更新 DOM 的核心,Vue3 用 Proxy 替代 Vue2 的 Object.defineProperty,解决了历史痛点,同时提升性能。
(一)核心逻辑
数据劫持:通过 Proxy 包装目标对象,拦截「读取(get)」「修改(set)」「删除(deleteProperty)」等操作。
✅ 支持场景:对象新增属性(obj.newKey = 1)、数组索引修改(arr[0] = 2)、数组方法(push/pop),无需额外处理。
依赖收集:当组件渲染、watch 回调执行时,会读取响应式数据,此时触发 Proxy.get 拦截,记录「数据 → 依赖(组件 / 函数)」的映射关系,存储在全局容器中。
例:组件渲染时用到 user.name,则将该组件标记为 user.name 的依赖。
触发更新:当数据被修改(如 user.name = '新值'),触发 Proxy.set 拦截,从容器中找到所有依赖,通知它们重新执行(组件重新渲染、watch 回调触发)。
与 Vue2 关键差异
|------|-----------------------------|------------------|---------------------|
| 特性 | Vue2(Object.defineProperty) | Vue3(Proxy) | 实际影响 |
| 监听范围 | 仅能监听已声明属性 | 对象所有属性(含新增 / 删除) | 无需 Vue.set,直接赋值新增属性 |
| 数组支持 | 需重写 push/pop 等 7 个方法 | 原生数组方法 + 索引直接支持 | 数组操作更自然,无隐藏限制 |
| 嵌套对象 | 初始化时递归遍历所有属性 | 访问嵌套属性时才懒递归代理 | 大对象初始化速度提升明显特性 |
| 性能 | 初始化开销大(遍历全属性) | 懒初始化 + 按需拦截 | 大型项目启动更快,内存占用更低 |
简单示例
javascript
// Vue3 响应式用法
import { reactive, watch } from 'vue';
const user = reactive({ name: '张三', age: 20 });
// 依赖收集:watch 回调是 user.name 的依赖
watch(() => user.name, (newVal) => {
console.log('名字变了:', newVal);
});
// 触发更新:修改 user.name,自动执行 watch 回调
user.name = '李四'; // 控制台输出:名字变了:李四
// 支持新增属性(Vue2 不支持)
user.gender = '男'; // 自动成为响应式属性
二、组件渲染
Vue3 组件渲染的核心是「虚拟 DOM(VNode)」,通过「编译→生成→渲染 / 更新」三步完成,相比 Vue2 优化了编译逻辑和更新效率。
(一)核心流程
1. 模板编译:Template → Render 函数
Vue3 编译器会将 .vue 中的 <template> 转为渲染函数(render),同时做 2 个关键优化:
- PatchFlag 标记:给动态节点打标记,比如 {{ message }} 标记为「仅文本变化」,v-bind:class 标记为「仅类名变化」。
2. 生成 VNode:Render 函数 → 虚拟 DOM
组件挂载 / 更新时,执行 render 函数,生成 VNode 树(虚拟 DOM)。VNode 是对真实 DOM 的抽象描述,包含「节点类型(标签 / 组件)、属性、子节点」等信息,避免直接操作 DOM 的性能开销。
3. 渲染 / 更新:VNode → 真实 DOM
- 首次挂载(mount):将 VNode 树转为真实 DOM,插入页面容器;
- 数据变化(patch):生成新的 VNode 树,对比新旧 VNode,根据「PatchFlag 标记」只更新变化部分(如仅更新文本,不触碰其他节点),大幅提升更新效率。
三、Composition API
Vue3 推出 Composition API(setup 函数 +ref/reactive/watch 等),核心解决 Vue2 Options API 「逻辑分散、复用困难」的问题。
(一)核心原理
执行时机
setup 函数在组件「创建前」执行(介于 beforeCreate 和 created 之间),此时无 this,但可通过参数获取 props 和 emit。
响应式关联
reactive:用于对象 / 数组的响应式,返回代理对象;
ref:用于基本类型(number/string/boolean)的响应式,底层通过 reactive 包装({ value: 原始值 }),访问时需用 .value(模板中可省略)。
生命周期钩子
onMounted/onUpdated 等钩子,本质是「注册回调函数」,在组件对应生命周期阶段自动执行。
四、性能优化
1. 编译时优化(模板编译阶段)
- 静态提升:静态节点 / 属性提升到渲染函数外部,复用已有节点;
- PatchFlag 标记:精准标记动态部分,更新时跳过静态内容;
- 事件缓存:内联事件函数(如 @click="handleClick")缓存到组件实例,避免每次渲染创建新函数。
2. 运行时优化(代码执行阶段)
- Proxy 懒初始化:响应式数据只有被访问时才触发代理,大对象初始化更快;
- 虚拟 DOM 按需更新:基于 PatchFlag 和 shapeFlag,减少对比次数;
- 内存优化:用 WeakMap/WeakSet 存储依赖,便于垃圾回收;组件卸载时自动清理依赖,避免内存泄漏。