解释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 操作等)
相关推荐
IT_陈寒1 小时前
Redis缓存击穿把我整不会了,原来还有这手操作
前端·人工智能·后端
idcu2 小时前
深入 Lyt.js 组件系统:L2 渲染引擎层的核心
前端·typescript
kyriewen2 小时前
面试官让我查各部门工资最高的员工,我用AI三秒写出窗口函数,他愣了
后端·mysql·面试
这是程序猿2 小时前
Spring Boot自动配置详解
java·大数据·前端
文心快码BaiduComate2 小时前
干货|Comate Harness Engineering工程实践指南
前端·后端·程序员
还有多久拿退休金2 小时前
一张栈的图,治好你面试答不出 script 阻塞的病
前端·javascript
光辉GuangHui2 小时前
Agent Skill 也需要测试:如何搭建 Skill 评估框架
前端·后端·llm
To_OC2 小时前
我终于搞懂 Claude Code 核心逻辑!90%的人都用错了模式
前端·ai编程
蓝宝石的傻话2 小时前
Headless浏览器的隐形陷阱:为什么你的AI自动化工具抓不到页面早期错误?
前端
irving同学462382 小时前
Node 后端实战:JWT 认证与生产级错误处理
前端·后端