解释watch和computed的原理

1️⃣ 核心区别表

特性 computed watch
用途 计算衍生数据 监听变化执行副作用
返回值 会返回值并缓存 无返回值(主要触发回调)
执行时机 访问 .value 时才执行 数据变化时立即触发(flush 可控制)
缓存机制 ✅ 会缓存,依赖未变不重新计算 ❌ 不缓存,每次依赖变化都会触发回调
依赖收集 自动收集依赖 需手动指定监听对象(或 watchEffect 自动收集)
可获取 oldValue
异步支持 ❌ 仅同步计算 ✅ 可做异步副作用(API、DOM 操作等)
适合场景 纯逻辑计算、UI 展示数据 副作用逻辑、异步请求、操作 DOM 等

2️⃣ 理解方式

  1. computed = 计算属性(惰性求值 + 缓存)

    • 主要用于根据已有数据计算出新的数据
    • 访问 value 时才触发计算
    • 不适合做副作用
  2. watch = 数据侦听器(观察者模式)

    • 用于监听某个响应式变量变化
    • 触发回调执行副作用(API 请求、DOM 操作、日志等)
    • 可访问新旧值
    • 可以做异步操作

3️⃣ 原理上的差异

  • computed

    • 内部有 effect + dirty flag
    • 依赖变化时标记 dirty = true
    • 下一次访问 value 时重新计算
    • 可以缓存,减少重复计算
  • watch

    • 直接对响应式数据注册 effect
    • 数据变化时立即触发回调
    • 回调不返回值
    • 可选择 flush:pre/post/sync 控制执行时机

computed 的原理

computed 本质上是一个 带缓存的响应式副作用

  1. 依赖收集

    • 当访问 computed.value 时,Vue 会触发其内部 effect,追踪它依赖的响应式数据(ref 或 reactive 对象)。
  2. 惰性求值(lazy)

    • 初次访问时执行 getter,生成值并缓存
    • 标记 dirty = false
  3. 缓存机制

    • 当依赖变化时,响应式系统会将 dirty = true
    • 下次访问 .value 时重新计算并更新缓存
  4. 不可获取旧值

    • 因为 computed 只关注最新值,内部只存当前缓存

示意流程:

ini 复制代码
访问 computed.value → 检查 dirty
    ├─ dirty = true → 执行 getter → 缓存值 → dirty = false
    └─ dirty = false → 直接返回缓存值
依赖变化 → effect 标记 dirty = true

示例代码:

arduino 复制代码
import { ref, computed } from 'vue'

const count = ref(1)
const double = computed(() => count.value * 2)

console.log(double.value) // 2
count.value++
console.log(double.value) // 4,重新计算

2️⃣ watch 的原理

watch 本质是一个 响应式数据的观察者(Watcher) ,用于执行副作用:

  1. 手动依赖选择

    • 你传入要监听的响应式对象(ref / reactive / getter)
    • Vue 内部会对其注册 effect
  2. 响应式触发

    • 当被监听的数据发生变化时,effect 会触发回调函数
  3. 可获取 oldValue / newValue

    • watch 在触发时会提供新值和旧值
  4. 异步可选

    • 默认 flush: 'pre'
    • 可以指定 'post'(DOM 更新后)或 'sync'(同步执行)
  5. 没有缓存

    • 每次数据变化都会调用回调函数
    • 适合副作用逻辑,不用于纯计算

示意流程:

scss 复制代码
watch(reactiveData, callback)
    └─ 内部创建 effect
依赖变化 → 触发 effect → callback(newValue, oldValue)

示例代码:

javascript 复制代码
import { ref, watch } from 'vue'

const count = ref(1)

watch(count, (newVal, oldVal) => {
  console.log(`count changed from ${oldVal} to ${newVal}`)
})

count.value++  // 触发 watch 回调

3️⃣ 原理总结对比

特性 computed watch
内部机制 effect + dirty flag effect 直接触发回调
触发时机 访问 .value 时(懒执行) 数据变化时立即触发
缓存 ✅ 缓存上次计算值 ❌ 不缓存,每次触发回调
oldValue ❌ 无 ✅ 有
使用目的 衍生数据计算 执行副作用(异步、DOM 操作等)
相关推荐
前端一课1 小时前
【vue高频面试题】第 18 题:Vue3 响应式原理中的 effect、依赖收集与依赖触发
前端·面试
前端一课1 小时前
【vue高频面试题】第 19 题:Vue3 性能优化技巧
前端·面试
前端一课1 小时前
【vue高频面试题】第 15 题:computed vs watch 区别 + 使用场景
前端·面试
前端一课1 小时前
【vue高频面试题】第 20 题:Vue3 生命周期 + watch 执行顺序
前端·面试
前端一课1 小时前
【vue高频面试题】第 16 题:Vue3 响应式原理深度解析(Proxy + effect 栈 + 依赖追踪)
前端·面试
执笔论英雄1 小时前
【大模型推理】小白教程:vllm 异步接口
前端·数据库·python
炒毛豆1 小时前
vue3+ant design vue实现表单验证失败后,自动滚动到失败的位置(scrollToField)
前端·javascript·vue.js
IT_陈寒1 小时前
Vite 5个隐藏功能大揭秘:90%的开发者都不知道这些提速技巧!
前端·人工智能·后端