技术知识文章集合TECHNICAL ARCHIVE · 457 DOCUMENTS

显示模式

登录
ARCHIVE DOCUMENTVUE

Vue3与Vue2的差异:更好的响应式数据更新

所属馆藏
Vue
文件格式
Markdown
原始路径
Vue/26-Vue3与Vue2的差异:更好的响应式数据更新
本文目录4 个章节
  1. 一、Vue 3 的 Proxy 机制与 Vue 2 的 Object.defineProperty
  2. 二、Vue 3 的 reactive 与 Vue 2 的 Vue.observable
  3. 总结
  4. 官方参考

Vue3与Vue2的差异:更好的响应式数据更新

Vue 3 在响应式数据更新方面的重要变化,是以 Proxy 为基础实现 reactive(),而 Vue 2 主要依赖 Object.defineProperty()。下面保留原文的两部分对照、代码示例和总结,并修正版本边界。

一、Vue 3 的 Proxy 机制与 Vue 2 的 Object.defineProperty

Vue 2 会在初始化时递归观察已有的嵌套对象属性,并为已有属性安装 getter/setter。它也包装了数组的 pushpopshiftunshiftsplicesortreverse 七个变异方法,因此“Vue 2 无法监听嵌套对象和数组”并不准确。

Vue 2 真正的常见边界是:

  • 初始化后直接新增或删除对象属性。
  • 通过索引直接修改数组元素。
  • 直接修改数组 length

旧项目可使用 Vue.set / $setVue.delete / $deletesplice 绕过这些边界。

Vue 3 使用 Proxy 拦截目标对象上的操作,包括属性读取、写入、删除、键检查和枚举等。下面保留原文的原生 Proxy 实验,并修正为 Reflect.get() / Reflect.set()

const data = { count: 0 }

const loggingProxy = new Proxy(data, {
  get(target, key, receiver) {
    console.log(`正在访问属性 ${String(key)}`)
    return Reflect.get(target, key, receiver)
  },
  set(target, key, value, receiver) {
    console.log(`正在设置属性 ${String(key)}${String(value)}`)
    return Reflect.set(target, key, value, receiver)
  }
})

console.log(loggingProxy.count)
loggingProxy.count = 1
console.log(loggingProxy.count)

set trap 必须返回表示操作成功与否的布尔值,使用 Reflect.set() 可以正确转发默认语义及 receiver

需要强调:这个示例只是日志代理,不是 Vue 响应式。它没有 Vue 的 track()trigger()、effect 调度和代理缓存,不会自动让 DOM 或副作用函数更新。原生 Proxy 也只代理当前 target 一层;Vue 的深层响应式来自 reactive() 对访问到的嵌套对象继续包装。

二、Vue 3 的 reactive 与 Vue 2 的 Vue.observable

Vue 2.6 的 Vue.observable(obj) 会按 Vue 2 Observer 规则观察传入 plain object,包括初始化时已有的嵌套对象和数组。它并非“只适用于根级对象”,但仍受 Vue 2 新增/删除键、数组索引和 length 边界限制。

Vue 3 中对应的主要 API 是 reactive()。下面用 watchEffect() 证明响应式依赖会更新,而不只是赋值前后手动打印:

import { reactive, watchEffect } from 'vue'

const raw = {
  count: 0,
  nested: { value: 1 },
  items: []
}

const state = reactive(raw)

watchEffect(() => {
  console.log('effect:', state.nested.value, state.items.length)
})

state.nested.value = 2
state.items.push('Vue')
state.items[0] = 'Vue 3'

watchEffect() 会先立即执行,并在其同步读取的依赖变化后再次执行。这比普通 console.log() 更能说明 Vue 响应式更新。

使用 reactive() 时还要注意:

  • reactive(raw) !== raw,返回值是 Proxy。
  • 深层代理由 Vue 在访问嵌套对象时完成;这不是原生 Proxy 自动递归。
  • 同一个 raw 对象重复传给 reactive() 会得到同一代理。
  • 应持续读写代理 state,不要直接修改 raw 并期待触发依赖。
  • reactive() 只接受对象类型;原始值通常使用 ref()

总结

Vue 2 通过递归观察已有属性和包装七个数组变异方法实现响应式,并非完全不能观察嵌套对象或数组;它的主要缺口是对象属性新增/删除、数组索引和 length 的直接操作。

Vue 3 以 Proxy 为基础,让 reactive() 能覆盖这些操作。Proxy 只是语言层的一层拦截机制,Vue 还需要依赖收集、派发更新、深层包装及调度等完整实现。开发时应使用 reactive() 返回的代理,并用组件渲染、watch()watchEffect() 消费响应式状态。

Vue 2 已结束维护,新项目建议使用 Vue 3;Vue 2 内容适用于维护历史项目。

官方参考

457 DOCUMENTS · 10 COLLECTIONS
ARCHIVE SEARCH457 篇文章

SEARCH GUIDE

输入关键词开始搜索

支持搜索文章标题、所属分类和原始文档路径。

按分类浏览

10 COLLECTIONS