Vue3 响应式革命

Vue2 验证了「响应式驱动视图」的威力,却在数组索引、属性增删等场景留下无法追踪的死角。Vue3 并未缝缝补补,而是把整座大厦的地基------数据拦截机制------彻底替换为 Proxy。本文沿着「拦截 → 创建 → 收集」三条链路,带你读懂这一次底层跃迁的全部细节。

一、拦截:从点到面的语义升级

1.Vue2 的「定点拦截」

Object.defineProperty 只能劫持已存在的属性。当业务代码 obj.newKey = 1 时,这条新增路径对依赖系统完全不可见,于是官方只能额外暴露 Vue.set / vm.$set 作为补丁。

2.Vue3 的「整面拦截」

Proxy 把「对象」视为一个整体,任何对属性的 读取、写入、删除、遍历 乃至 原型链读取 都能被捕获。

ts 复制代码
const p = new Proxy(obj, {
  get(target, key, receiver) { /* 读 */ },
  set(target, key, value, receiver) { /* 写 */ },
  deleteProperty(target, key) { /* 删 */ }
})

新增 key 不再逃逸,数组索引与 length 的变化自然落入监听范围,彻底告别 $set

二、创建:ref 与 reactive 的分工

虽然 Proxy 能力更强,但「原始值」无法被代理。Vue3 用 RefImpl 与 ReactiveImpl 两套实现互补:

  • ref 负责原始值(Number、String、Boolean)------内部用 RefImpl 包裹,读/写时触发自定义 getter/setter;当值是对象时再递归交给 reactive
  • reactive 负责对象/数组------直接返回 Proxy,拦截全部操作。

源码片段(精简):

ts 复制代码
class RefImpl<T> {
  get value() {
    track(this, 'value')   // 收集
    return this._value
  }
  set value(newVal) {
    this._value = toReactive(newVal)
    trigger(this, 'value') // 派发
  }
}

function reactive(target: object) {
  return createReactiveObject(target, mutableHandlers)
}

toReactive 判断传入值是否为对象,是则继续包 Proxy,否则原样返回,形成一条「层层代理,按需终止」的链。

三、收集:从 Watcher 树到副作用图

1.Vue2 的 Watcher + Dep

每个响应式属性拥有一个 Dep,Dep 里存着若干 Watcher(通常是一个组件渲染函数)。属性变化 → 通知所有 Watcher → 组件级重渲染。

粒度:组件级别。

2.Vue3 的副作用图

Vue3 不再关心「是哪个组件」,而是关心「哪个副作用函数」。数据结构是一张 WeakMap → Map → Set 的三级表:

  • 第一级 WeakMap:键是响应式对象,值是第二级 Map;
  • 第二级 Map:键是属性名,值是第三级 Set;
  • 第三级 Set:存储所有依赖该属性的 effect 函数。

当属性值改变时,只触发 精确到函数 的重新执行,粒度从组件级降到函数级,更新范围更小,性能更高。

四、工程实践的迁移

  • Vue2 项目:若观察到大量 this.$setVue.set,说明已踩中响应式盲区,升级 Vue3 可一次性消除。
  • 新 Vue3 项目:优先使用 reactive 管理对象,ref 管理原始值;避免把 reactive 包进 ref,防止双重代理带来的额外开销。
  • 性能调优:借助 markRawshallowReactive 把大列表、第三方库实例标记为非响应式,减少追踪压力。

结语

Vue3 的响应式不是「打补丁」,而是「换引擎」。Proxy 让「增删改查」全部可追踪,WeakMap 让依赖收集更精准。这次底层跃迁,彻底解决了 Vue2 的响应式难题,也为 Vue3 的性能优化奠定了基础。

相关推荐
Zhencode2 分钟前
Vue3 响应式依赖收集与更新之effect
前端·vue.js
x-cmd6 分钟前
[x-cmd] jsoup 1.22.1 版本发布,引入 re2j 引擎,让 HTML 解析更安全高效
前端·安全·html·x-cmd·jsoup
天下代码客23 分钟前
使用electronc框架调用dll动态链接库流程和避坑
前端·javascript·vue.js·electron·node.js
weixin199701080161 小时前
【性能提升300%】仿1688首页的Webpack优化全记录
前端·webpack·node.js
冰暮流星1 小时前
javascript之数组
java·前端·javascript
晚霞的不甘1 小时前
Flutter for OpenHarmony天气卡片应用:用枚举与动画打造沉浸式多城市天气浏览体验
前端·flutter·云原生·前端框架
weixin79893765432...1 小时前
Vue 渲染体系“三件套”(template 模板语法、h 函数和 JSX 语法)
vue.js·h函数·template 模板·jsx 语法
xkxnq2 小时前
第五阶段:Vue3核心深度深挖(第74天)(Vue3计算属性进阶)
前端·javascript·vue.js
三小河2 小时前
Agent Skill与Rules的区别——以Cursor为例
前端·javascript·后端
Hilaku2 小时前
不要在简历上写精通 Vue3?来自面试官的真实劝退
前端·javascript·vue.js