Vue计算属性vs侦听器:什么时候用computed?什么时候用watch?老司机一次讲透!

大家好,我是小杨,一个写了6年前端的Vue钉子户。今天咱们来解决一个永恒的灵魂拷问:computed和watch到底用哪个? 这俩兄弟长得像但脾气完全不同,新手经常用错。看完这篇,保证你从此选得明明白白!

先来个生活化比喻

  • computed:就像你的智能助理,你告诉它:"帮我盯着牛奶和咖啡的库存,快没的时候提醒我"。它会自动计算,只在相关库存变化时才通知你。
  • watch:就像雇了个私家侦探,你命令他:"24小时盯着我女朋友的微信步数,只要变化就立即报告我!"。不管有没有用,变化一次就报告一次。

代码对比:一看就懂

场景1:显示用户全名

用computed的正确姿势

javascript 复制代码
data() {
  return {
    firstName: '张',
    lastName: '三'
  }
},
computed: {
  fullName() {
    return `${this.firstName} ${this.lastName}` 
  }
}
// 模板中直接使用:{{ fullName }}

用watch的错误示范

javascript 复制代码
data() { 
  return {
    firstName: '张',
    lastName: '三',
    fullName: ''
  }
},
watch: {
  firstName(val) {
    this.fullName = `${val} ${this.lastName}`
  },
  lastName(val) {
    this.fullName = `${this.firstName} ${val}`
  }
}
// 模板中:{{ fullName }}

区别一眼可见:

  • computed更简洁,自动追踪依赖
  • watch需要手动处理每个依赖项
  • computed有缓存,相同值不重复计算

场景2:搜索请求防抖

watch的专属舞台

javascript 复制代码
data() {
  return {
    searchQuery: '',
    searchResults: []
  }
},
watch: {
  searchQuery(newVal) {
    // 只有在这里才需要手动防抖!
    this.debouncedSearch(newVal)
  }
},
created() {
  this.debouncedSearch = _.debounce(this.doSearch, 500)
},
methods: {
  doSearch(query) {
    axios.get('/search', { params: { q: query } })
      .then(res => this.searchResults = res.data)
  }
}

为什么不用computed?

因为这里需要的是副作用(发起请求),而不是计算一个值!

核心区别表格对比

特性 computed watch
用途 计算新值 监听变化执行操作
缓存 有(依赖不变直接返回缓存) 无(每次变化都执行)
异步 不能 可以
返回值 必须return 不需要return
适用场景 模板中使用的派生数据 数据变化时需要执行副作用操作

我踩过的三个大坑

  1. 在computed里修改data

    曾经我这样写:

    javascript 复制代码
    computed: {
      userInfo() {
        this.user.age = 30 // 千万不要这样!
        return {...this.user}
      }
    }

    结果导致无限循环更新!computed应该是个纯函数

  2. 用watch监听复杂对象

    javascript 复制代码
    watch: {
      user() {
        // 对象内部变化不会触发!
      }
    }

    解决方案:

    javascript 复制代码
    watch: {
      user: {
        handler() { /* 处理逻辑 */ },
        deep: true // 开启深度监听
      }
    }
  3. 过度使用watch

    新手常犯的错误:

    javascript 复制代码
    // 错误示范:能用computed偏要用watch
    watch: {
      firstName() { /* 更新fullName */ },
      lastName() { /* 更新fullName */ }
    }

    这种场景明显应该用computed!

性能优化指南

  1. 多用computed少用watch

    computed有缓存机制,相同值不重复计算。我曾经优化过一个页面,把10个watch改成computed,渲染速度提升了40%!

  2. watch的immediate和deep慎用

    javascript 复制代码
    watch: {
      user: {
        handler() { /* 逻辑 */ },
        deep: true,    // 深度监听影响性能
        immediate: true // 立即执行可能不需要
      }
    }
  3. 大对象用computed分拆

    javascript 复制代码
    data() {
      return {
        bigData: { /* 超大对象 */ }
      }
    },
    computed: {
      importantPart() {
        return this.bigData.importantPart
      }
    }

    这样只有importantPart变化才会触发更新

终极选择流程图

plaintext 复制代码
需要根据其他数据计算新值?  
  ├─ 是 → computed
  └─ 否 → 需要在数据变化时执行操作?  
           ├─ 是 → watch
           └─ 否 → 可能都不需要!

⭐ 写在最后

请大家不吝赐教,在下方评论或者私信我,十分感谢🙏🙏🙏.

✅ 认为我某个部分的设计过于繁琐,有更加简单或者更高逼格的封装方式

✅ 认为我部分代码过于老旧,可以提供新的API或最新语法

✅ 对于文章中部分内容不理解

✅ 解答我文章中一些疑问

✅ 认为某些交互,功能需要优化,发现BUG

✅ 想要添加新功能,对于整体的设计,外观有更好的建议

✅ 一起探讨技术加qq交流群:906392632

最后感谢各位的耐心观看,既然都到这了,点个 👍赞再走吧!

相关推荐
旧梦吟7 分钟前
脚本网页 地球演化
前端·算法·css3·html5·pygame
xiaoxue..10 分钟前
哨兵节点与快慢指针解决链表算法难题
前端·javascript·数据结构·算法·链表
这是个栗子11 分钟前
【前端知识点总结】前端跨域问题
前端·跨域·cors
尽欢i16 分钟前
踩过坑才懂:前端生成唯一 ID,别用 Date.now ()了!一行代码搞定
前端·javascript
JS_GGbond16 分钟前
解锁 JavaScript 对象的“魔法宝箱”:这些方法让你玩转对象操作
前端·javascript
Doris89319 分钟前
【JS】JS进阶--编程思想、面向对象构造函数、原型、深浅拷贝、异常处理、this处理、防抖节流
开发语言·javascript·ecmascript
是杉杉吖~21 分钟前
《5 分钟上手 React Flex 容器:从 0 搭建响应式卡片列表》
前端·react.js·前端框架
福大大架构师每日一题22 分钟前
rust 1.92.0 更新详解:语言特性增强、编译器优化与全新稳定API
java·javascript·rust
仰望.23 分钟前
vue 甘特图 vxe-gantt table 拖拽任务调整开始日期和结束日期的使用,拖拽任务调整日期
vue.js·甘特图·vxe-ui
阿懂在掘金24 分钟前
早点下班:在 Vue3 中少写 40%+ 的异步代码
vue.js