vue3响应式(双向数据绑定)原理和vue2的区别

159 阅读4分钟

vue3响应式(双向数据绑定)原理和vue2的区别

Vue 3 的响应式系统与 Vue 2 有显著的不同,Vue 3 使用了 Proxy 替代了 Vue 2 中的 Object.defineProperty,从而带来了更好的性能和更强大的功能。以下是 Vue 3 和 Vue 2 响应式原理的详细对比:

  1. Vue 2 的响应式原理

实现方式

Vue 2 使用 Object.defineProperty 来实现响应式。它会遍历对象的每个属性,将其转换为 getter 和 setter。

核心步骤:

初始化阶段

  • 遍历对象的每个属性,使用 Object.defineProperty 将其转换为 getter 和 setter。

  • 在 getter 中收集依赖(将当前 Watcher 添加到 Dep 中)。

  • 在 setter 中触发更新(通知 Dep 中的所有 Watcher 更新)。

依赖收集

  • 每个属性都有一个对应的 Dep 实例,用于存储依赖(Watcher)。

  • 当属性被访问时,当前 Watcher 会被添加到 Dep 中。

派发更新

  • 当属性被修改时,会触发 setter,通知 Dep 中的所有 Watcher 更新。
// Vue 2 响应式实现(简化版)
function defineReactive(obj, key, val) {
  const dep = new Dep(); // 每个属性都有一个 Dep 实例

  Object.defineProperty(obj, key, {
    get() {
      if (Dep.target) {
        dep.addSub(Dep.target); // 收集依赖
      }
      return val;
    },
    set(newVal) {
      if (newVal === val) return;
      val = newVal;
      dep.notify(); // 派发更新
    },
  });
}

局限性:

无法检测新增属性

  • Vue 2 无法检测到对象属性的新增或删除(需要使用 Vue.setVue.delete)。

数组的限制

  • Vue 2 无法直接检测数组索引的变化(如 arr[0] = 1)和数组长度的变化(如 arr.length = 0)。

性能问题

  • 初始化时需要递归遍历对象的每个属性,性能较差。
  1. Vue 3 的响应式原理

实现方式

Vue 3 使用 Proxy 来实现响应式。Proxy 是 ES6 的特性,可以拦截对象的操作(如读取、赋值、删除等)。

核心步骤:

初始化阶段

  • 使用 new Proxy() 创建一个代理对象。

  • 在代理对象中拦截属性的读取(get)和赋值(set)操作。

依赖收集

  • 在 get 拦截器中收集依赖(将当前 effect 添加到依赖集合中)。

派发更新

  • 在 set 拦截器中触发更新(通知依赖集合中的所有 effect 更新)。
// Vue 3 响应式实现(简化版)
function reactive(obj) {
  return new Proxy(obj, {
    get(target, key, receiver) {
      track(target, key); // 收集依赖
      return Reflect.get(target, key, receiver);
    },
    set(target, key, value, receiver) {
      const result = Reflect.set(target, key, value, receiver);
      trigger(target, key); // 派发更新
      return result;
    },
  });
}

优势:

支持新增和删除属性

  • Proxy 可以拦截属性的新增和删除操作,无需额外 API。

更好的数组支持

  • Proxy 可以直接检测数组索引和长度的变化。

性能优化

  • Proxy 是惰性的,只有在访问属性时才会进行依赖收集,性能更好。

更强大的拦截能力

  • Proxy 可以拦截更多操作(如 indeleteObject.keys 等)。
  1. Vue 3 响应式系统的底层原理

Vue 3 的响应式系统基于 EffectDep 实现。

Effect

  • Effect 是一个副作用函数,当响应式数据变化时,Effect 会被重新执行。

  • Vue 3 使用 effect 函数来创建 Effect。

Dep

  • Dep 是一个依赖集合,用于存储所有依赖于某个属性的 Effect。

Track 和 Trigger

  • track:在 get 拦截器中调用,用于收集依赖。

  • trigger:在 set 拦截器中调用,用于触发更新。

  1. Vue 3 与 Vue 2 响应式系统的对比
特性Vue 2Vue 3
实现方式使用 Object.defineProperty使用 Proxy
新增属性检测不支持(需使用 Vue.set)支持
数组支持不支持直接检测索引和长度变化支持
性能初始化时需要递归遍历,性能较差惰性依赖收集,性能更好
拦截能力只能拦截属性的读取和赋值可以拦截更多操作(如 in、delete)
API基于 Options API支持 Composition API 和 Options API

总结

  • Vue 2 使用 Object.defineProperty 实现响应式,存在一些局限性(如无法检测新增属性、数组变化等)。

  • Vue 3 使用 Proxy 实现响应式,性能更好,功能更强大,支持更多操作。

  • Vue 3 的响应式系统基于 reactiverefcomputedwatch 等 API,提供了更灵活的开发方式。

更多vue相关插件及后台管理模板可访问vue admin reference,代码详情请访问github