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,帮助开发者更好地管理和操作响应式对象。

相关推荐
人工智能训练师12 小时前
Ubuntu22.04如何安装新版本的Node.js和npm
linux·运维·前端·人工智能·ubuntu·npm·node.js
Seveny0712 小时前
pnpm相对于npm,yarn的优势
前端·npm·node.js
yddddddy13 小时前
css的基本知识
前端·css
昔人'13 小时前
css `lh`单位
前端·css
前端君14 小时前
实现最大异步并发执行队列
javascript
Nan_Shu_61415 小时前
Web前端面试题(2)
前端
知识分享小能手15 小时前
React学习教程,从入门到精通,React 组件核心语法知识点详解(类组件体系)(19)
前端·javascript·vue.js·学习·react.js·react·anti-design-vue
蚂蚁RichLab前端团队16 小时前
🚀🚀🚀 RichLab - 花呗前端团队招贤纳士 - 【转岗/内推/社招】
前端·javascript·人工智能
孩子 你要相信光16 小时前
css之一个元素可以同时应用多个动画效果
前端·css
萌萌哒草头将军16 小时前
Oxc 和 Rolldown Q4 更新计划速览!🚀🚀🚀
javascript·vue.js·vite