Vue 的响应式原理

1. 数据劫持

① Vue 2 使用defineproperty()

在 Vue 2.x 中,Vue 使用 Object.defineProperty() 来拦截对象属性的getter和setter。每当一个 Vue 实例被创建时,它会遍历所有传入的数据对象的属性,并将它们转换为 getter 和 setter。

javascript 复制代码
// 简化版示例
function defineReactive(obj, key, val) {
  Object.defineProperty(obj, key, {
    get: function reactiveGetter() {
      // 收集依赖
      return val;
    },
    set: function reactiveSetter(newVal) {
      if (newVal === val) return;
      val = newVal;
      // 触发更新
    }
  });
}

局限性:

  • 它不能检测到新增或删除属性。
  • 对于数组的操作无法直接拦截,因此 Vue 需要重写数组的部分方法来实现响应式。

② Vue 3 使用 Proxy

从 Vue 3 开始,Vue 引入了 ES6 的 Proxy 来替代 Object.defineProperty()Proxy 提供了更强大的功能,可以拦截更多的操作类型,如添加新属性、删除属性等,并且可以递归地处理嵌套对象,而不需要像 Object.defineProperty() 那样手动遍历每个属性。

javascript 复制代码
// 简化版示例
const handler = {
  get(target, key, receiver) {
    // 收集依赖
    return Reflect.get(target, key, receiver);
  },
  set(target, key, value, receiver) {
    const result = Reflect.set(target, key, value, receiver);
    // 触发更新
    return result;
  }
};
const proxy = new Proxy(data, handler);

2. 依赖收集

Vue 使用观察者模式来实现依赖收集。每当渲染组件时,Vue 会执行模板中表达式的 getter,从而触发依赖收集过程。在此过程中,Vue 会记录哪些 watcher 订阅了特定的数据属性的变化。

  • Watcher:每一个需要响应数据变化的地方(例如,计算属性、渲染函数)都有一个对应的 watcher。watcher 负责监听它所关心的数据属性的变化,并在变化发生时更新相关的视图部分。

  • Dep(依赖):每个响应式属性都有一个关联的 Dep 实例,用来管理所有订阅它的 watcher。当该属性发生变化时,Dep 会通知所有的 watcher 进行更新。

3. 视图更新机制

当用户交互或其他代码导致数据属性发生变化时,Vue 的响应式系统会调用该属性的 setter 方法。setter 不仅会设置新的值,还会通知所有订阅了该属性变化的 watcher。然后,这些 watcher 会重新评估并触发视图更新。

  • 异步队列 :为了提高性能,Vue 将所有的 DOM 更新操作批量放入一个异步队列中,在下一个事件循环 tick 时统一执行。这减少了不必要的重绘和回流,提升了应用的效率。

    javascript 复制代码
    queueWatcher(watcher) {
      // 如果 watcher 已经在队列中,则跳过
      if (!watcher.id) {
        watcher.id = nextId++;
        queue.push(watcher);
      }
      // 批量更新
      nextTick(flushSchedulerQueue);
    }

4. 计算属性与侦听器

除了直接绑定到数据属性外,Vue 还提供了计算属性(computed properties)和侦听器(watchers),允许开发者基于现有数据派生出新的状态或者执行副作用操作。

  • 计算属性:计算属性是缓存的,只有在其依赖的数据发生变化时才会重新计算。它们非常适合用于复杂逻辑的推导或格式化输出。

  • 侦听器:侦听器则可以用来执行更复杂的逻辑,比如异步操作或开销较大的任务。侦听器可以在数据变化时立即执行,也可以指定深度监听。

5. Vue 3 中的改进

Vue 3 在多个方面对响应式系统进行了优化:

  • 更好的性能 :通过使用 Proxy 和更加高效的依赖跟踪机制,Vue 3 显著提高了响应式的性能。

  • 更简单的 API:引入了 Composition API,使得逻辑复用更加简单直观,同时支持 TypeScript 更加友好。

  • 细粒度的响应式 :Vue 3 提供了 reactiveref 两种方式来创建响应式对象,其中 ref 适用于单一值的响应式封装,而 reactive 则用于对象或数组。

  • 内置工具函数 :如 toRefsisRef,帮助开发者更好地管理和操作响应式对象。

相关推荐
請你喝杯Java41 分钟前
Mac软件清单(前后端开发环境搭建)
前端·后端·macos·软件
杨荧1 小时前
【开源免费】基于Vue和SpringBoot的渔具租赁系统(附论文)
前端·javascript·jvm·vue.js·spring boot·spring cloud·开源
小跳不会Coding1 小时前
vue实现【粘贴地址信息,自动拆分姓名、电话、地址】
javascript·vue.js·ecmascript
用户3623786912591 小时前
【面试题】说说你对发布订阅、观察者模式的理解?区别?_消息订阅与发布面试题
前端
想退休的搬砖人1 小时前
前端水印功能(svg,canvas文字水印,canvas图片水印)
开发语言·前端
王同学JavaNotes1 小时前
ES6 语法:强大特性全解析
前端·es6
GISer_Jing2 小时前
前端面试题目 (Node.JS-Express框架)[二]
前端·面试·node.js·express
别发呆了吧2 小时前
前端面试准备问题2
前端·经验分享
堂铭2 小时前
NextJS多语言
前端·i18n·nextjs
七月pro2 小时前
前端通过 jspdf 和 html2canvas 工具将网页生成 pdf
javascript·pdf