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

相关推荐
咖啡虫9 分钟前
css中的3d使用:深入理解 CSS Perspective 与 Transform-Style
前端·css·3d
烛阴20 分钟前
手把手教你搭建 Express 日志系统,告别线上事故!
javascript·后端·express
拉不动的猪29 分钟前
设计模式之------策略模式
前端·javascript·面试
旭久30 分钟前
react+Tesseract.js实现前端拍照获取/选择文件等文字识别OCR
前端·javascript·react.js
独行soc39 分钟前
2025年常见渗透测试面试题-红队面试宝典下(题目+回答)
linux·运维·服务器·前端·面试·职场和发展·csrf
uhakadotcom1 小时前
Google Earth Engine 机器学习入门:基础知识与实用示例详解
前端·javascript·面试
麓殇⊙1 小时前
Vue--组件练习案例
前端·javascript·vue.js
outstanding木槿1 小时前
React中 点击事件写法 的注意(this、箭头函数)
前端·javascript·react.js
会点php的前端小渣渣1 小时前
vue的计算属性computed的原理和监听属性watch的原理(新)
前端·javascript·vue.js
_一条咸鱼_2 小时前
深入解析 Vue API 模块原理:从基础到源码的全方位探究(八)
前端·javascript·面试