解释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 操作等)
相关推荐
FelixBitSoul1 分钟前
彻底吃透 React Hook:它背后的执行模型到底是什么? 🚀
前端
Huanzhi_Lin8 分钟前
Nginx本地资源服务器-常用脚本
服务器·前端·nginx·batch·静态资源服务器
weixin199701080168 分钟前
《好看视频商品详情页前端性能优化实战》
前端·性能优化·音视频
有意义9 分钟前
深入理解浏览器存储方案:从Cookie到JWT登录认证
前端·面试·浏览器
jiayong239 分钟前
第 6 课:第二轮真实重构,拆出任务表格组件
前端·重构
jiayong2316 分钟前
第 4 课:怎么把一个大页面拆成多个组件
运维·服务器·前端
skywalk816319 分钟前
使用DuMate帮助创建 Python 3.9 环境并部署 Kotti CMS
前端·chrome
英俊潇洒美少年23 分钟前
Vue Hook 与 React Hook 全面解析:区别、用法、实战及避坑指南
前端·vue.js·react.js
weixin_7042660530 分钟前
项目总结一
java·前端·spring boot·后端·spring
Mintopia30 分钟前
接口设计为什么越改越乱:新手最容易踩的三个坑
前端