← 返回文章列表
Vue·1136 次阅读

Vue 2 迁移 Vue 3(一):响应式原理之变

Vue 2 迁移 Vue 3(一):响应式原理之变

团队的老项目开始评估迁移,响应式系统是两代框架差异的根源,先把它搞透。

Vue 2:Object.defineProperty

核心是遍历 data 对象的每个属性,用 getter/setter 劫持读写:

function defineReactive(obj, key) {
  let val = obj[key]
  Object.defineProperty(obj, key, {
    get() {
      dep.depend() // 收集依赖:谁读了这个属性
      return val
    },
    set(newVal) {
      val = newVal
      dep.notify() // 通知更新
    },
  })
}

天生有两个短板:

  • 监听不到新增/删除属性——defineProperty 只能劫持初始化时已存在的 key,所以要 this.$set(obj, 'newKey', v) 打补丁
  • 数组下标和 length 监听不到——直接 arr[0] = x 不更新,Vue 只能重写 push/splice 等 7 个变异方法绕过
  • 深层对象要递归遍历到底,初始化开销大

Vue 3:Proxy

Proxy 代理整个对象,不关心具体有哪些 key:

function reactive(obj) {
  return new Proxy(obj, {
    get(target, key, receiver) {
      track(target, key) // 收集依赖
      const res = Reflect.get(target, key, receiver)
      return typeof res === 'object' ? reactive(res) : res // 懒代理:访问到才递归
    },
    set(target, key, value, receiver) {
      const result = Reflect.set(target, key, value, receiver)
      trigger(target, key) // 通知更新
      return result
    },
  })
}

改进是质变:

  • 新增属性、删除属性(delete)天然可拦截,$set 可以删了
  • 数组下标、length、Map/Set 全部支持
  • 只有被访问到的嵌套对象才代理,初始化快

注意 Proxy 代理的是对象,所以值类型才需要 ref(内部用 .value 的 getter/setter 包装)。

迁移注意点

  • 原来靠 $set/$delete 修的代码可以简化,但要检查有没有"依赖不触发更新"的隐性逻辑
  • 响应式判断:Vue.observable → reactive;Vue.observable 用法全部替换
  • Proxy 无法 polyfill,IE11 彻底不支持(需要兼容 IE 的项目只能留在 Vue 2.7)

下一篇讲组件写法和逻辑复用的迁移。

看到这里了?如果这篇文章帮到过你

请我喝瓶可乐就好 🥤

收款码

评论0 条

还没有评论,来抢沙发~

发表评论

评论需审核后显示

© 2026 许冬博客 · 专注 JS 技术分享

·RSS 订阅·Powered by Nuxt 4