Vue 2 vs Vue 3 核心差异深度解析

Vue 3 相比 Vue 2 带来了巨大的性能提升和架构改进。以下是两者在核心原理、开发体验和新特性上的主要区别。

1. 响应式系统原理 (核心区别)

这是 Vue 3 最底层的变革,直接决定了性能上限和开发体验。

Vue 2: Object.defineProperty 的局限

Vue 2 使用 ES5 的 Object.defineProperty API 来劫持对象的 getter 和 setter。

  • 初始化开销大:在组件初始化时,Vue 2 必须递归遍历 data 对象的所有属性(包括嵌套属性),将它们转换为 getter/setter。如果不访问这些属性,它们依然会被转换,这在数据量大时会造成明显的性能损耗。
  • 无法监听属性新增/删除:由于 JavaScript 的限制,Object.defineProperty 只能劫持已存在的属性。
    • this.obj.newProp = 123 不会触发视图更新。
    • 必须使用 Vue.set(this.obj, 'newProp', 123) 或 this.$set。
  • 数组监听缺陷:Vue 2 不能通过 Object.defineProperty 完美拦截数组索引的修改(如 arr[0] = 1)和长度修改(arr.length = 0)。
    • Vue 2 不得不重写(Monkey Patch)了数组的 7 个变异方法(push, pop, shift...)来实现响应式。

Vue 3: Proxy 的强大能力

Vue 3 使用 ES6 的 Proxy API,它不是劫持属性,而是代理整个对象。

  • 懒代理 (Lazy Observation):Proxy 默认只代理第一层。只有当你真正访问嵌套对象时,Vue 3 才会通过 Reflect 动态地将嵌套对象包装为 Proxy。这使得初始化速度极大提升,内存占用显著降低。
  • 动态属性支持:Proxy 可以拦截对象上任意属性的变化,包括新增属性和删除属性。
    • state.newProp = 123 直接生效。
  • 数组完美支持:Proxy 可以原生拦截数组索引修改和 length 变化,无需再重写数组方法。
  • 更多拦截操作:Proxy 可以拦截多达 13 种操作,包括 has (in 操作符), deleteProperty (delete 操作符) 等,这让 Vue 3 的响应式能力更全面。

深度对比表

特性Vue 2 (Object.defineProperty)Vue 3 (Proxy)
拦截粒度属性级别 (必须遍历所有 key)对象级别 (直接拦截整个对象)
初始化性能递归遍历,开销大懒代理,按需转换,快
新增/删除属性不支持 (需用 $set / $delete)原生支持
数组索引修改不支持 (需用 $set 或 splice)原生支持
Map / Set 支持不支持支持
Class 语法支持较弱支持
兼容性IE9+不支持 IE11 (因 Proxy 无法被 Polyfill)

伪代码原理解析

为了让你理解得更透彻,这里是两者实现的简化逻辑对比:

Vue 2 实现逻辑 (简化):

text
1234567891011121314151617181920
function defineReactive(obj, key, val) {
  // 必须针对每一个 key 进行定义
  Object.defineProperty(obj, key, {
    get() {
      // 收集依赖
      return val;
    },
    set(newVal) {
      if (newVal !== val) {
        val = newVal;
        // 触发更新
        updateView();
      }
    }
  });
}
// 初始化时必须立即递归遍历所有属性
for (const key in data) {
  defineReactive(data, key, data[key]);
}

Vue 3 实现逻辑 (简化):

text
12345678910111213141516171819202122232425
const handler = {
  get(target, key, receiver) {
    // 收集依赖 (track)
    const result = Reflect.get(target, key, receiver);
    // 懒代理:只有当属性值是对象且被访问时,才递归创建 Proxy
    return isObject(result) ? reactive(result) : result;
  },
  set(target, key, value, receiver) {
    const oldValue = target[key];
    const result = Reflect.set(target, key, value, receiver);
    // 触发更新 (trigger)
    if (oldValue !== value) {
      updateView();
    }
    return result;
  },
  deleteProperty(target, key) {
    // 还能拦截 delete 操作
    const result = Reflect.deleteProperty(target, key);
    updateView();
    return result;
  }
};
// 不需要预先遍历 key,直接代理整个对象
const proxy = new Proxy(data, handler);

2. API 风格:Options API vs Composition API

这是开发者感受最直观的变化。

Vue 2: Options API (选项式 API)

代码按照 data, methods, computed, watch 等选项块进行组织。

  • 优点:结构清晰,适合初学者,强制规范。
  • 缺点:当组件逻辑复杂时,同一功能的代码(比如“搜索功能”)会分散在 data、methods 等不同地方,导致代码难以阅读和维护("反复横跳")。

Vue 3: Composition API (组合式 API)

使用 setup() 函数(或 <script setup>),将逻辑关注点组织在一起。

  • 优点:逻辑复用极强(Hooks),类似 React Hooks;同一功能的代码集中在一起,易于维护;更好的类型推导。
  • 兼容性:Vue 3 依然完全支持 Options API。

代码对比

Vue 2 (Options API):

text
12345678910111213
export default {
  data() {
    return { count: 0 };
  },
  methods: {
    increment() {
      this.count++;
    }
  },
  mounted() {
    console.log('mounted');
  }
};

Vue 3 (Composition API - script setup):

text
12345678910111213141516
<script setup>
import { ref, onMounted } from 'vue';

// 状态定义
const count = ref(0);

// 方法定义
const increment = () => {
  count.value++;
};

// 生命周期
onMounted(() => {
  console.log('mounted');
});
</script>

3. 生命周期钩子 (Lifecycle Hooks)

Vue 3 对生命周期钩子进行了重命名,使其更语义化,并提供了对应 Composition API 的函数。

Vue 2 (Options API)Vue 3 (Options API)Vue 3 (Composition API)说明
beforeCreatebeforeCreatesetup()setup 执行时机更早
createdcreatedsetup()setup 取代了这两个钩子
beforeMountbeforeMountonBeforeMount
mountedmountedonMounted
beforeUpdatebeforeUpdateonBeforeUpdate
updatedupdatedonUpdated
beforeDestroybeforeUnmountonBeforeUnmount名称变更:销毁变成了卸载
destroyedunmountedonUnmounted名称变更
errorCapturederrorCapturedonErrorCaptured

4. 多根节点 (Fragments)

  • Vue 2: 组件模板必须有一个唯一的根元素。
  • Vue 3: 支持多根节点(Fragments)。Vue 3 会自动在虚拟 DOM 中创建一个 Fragment 节点来包裹它们,减少了不必要的 DOM 层级嵌套。

5. TypeScript 支持

  • Vue 2: 对 TypeScript 支持较弱。因为 this 上下文的动态性,很难进行完美的类型推导,通常需要使用 vue-class-component 装饰器写法,体验较为割裂。
  • Vue 3: 源码完全使用 TypeScript 重写。Composition API 天然对类型推导友好,不再依赖复杂的 this,开发体验极佳。

6. 新增内置组件与特性

Teleport (传送门)

允许将组件的 DOM 结构渲染到该组件 DOM 树之外的地方(例如直接挂载到 body 下),这对于制作模态框 (Modal)、通知 (Toast) 非常有用,避免了 z-index 层级冲突问题。

text
123
<Teleport to="body">
  <div class="modal">我是挂载在 body 下的模态框</div>
</Teleport>

Suspense (实验性)

允许在组件树中协调异步依赖的处理。可以在深层组件加载完成前,在父组件渲染一个“加载中”状态。

Tree Shaking (按需打包)

Vue 3 的全局 API(如 nextTick, set 等)改为 ES 模块导出。如果你不使用某个功能,打包工具可以将其摇掉(Remove),从而减小最终包的体积。

7. 全局 API 变更

Vue 2 使用 new Vue() 并修改 Vue 全局对象,这导致在同一页面运行多个 Vue 实例时容易相互污染。Vue 3 改为使用 createApp 创建应用实例。

text
1234567
// Vue 3 写法
import { createApp } from 'vue';
import App from './App.vue';

const app = createApp(App);
app.use(MyPlugin); // 仅影响当前实例
app.mount('#app');

总结

Vue 3 在性能(Proxy、Virtual DOM 优化)、可维护性(Composition API、TypeScript)和架构灵活性(Fragments、Teleport)上都全面优于 Vue 2。

如果是新项目,强烈建议直接使用 Vue 3 + Script Setup + TypeScript。