Vue 计算属性(computed)与监听器(watch)详解与对比

93 阅读4分钟

在 Vue.js 开发中,计算属性(computed)和监听器(watch)都是处理响应式数据变化的重要工具。本文将通过实际案例深入分析两者的特性、使用场景和核心区别。

一、计算属性(Computed)

1. 基本概念

计算属性是基于它们的响应式依赖进行缓存的计算值,只有当依赖的数据发生变化时才会重新计算。

2. 核心特性

缓存机制

javascript

复制下载

computed: {
  fullName: {
    get() {
      console.log('get被调用了');
      return this.firstName + '-' + this.lastName;
    },
    // 依赖的 firstName 或 lastName 不变时,多次访问 fullName 只会调用一次 get
  }
}

完整写法 vs 简写

完整写法(包含 getter 和 setter):

javascript

复制下载

computed: {
  fullName: {
    get() {
      return this.firstName + '-' + this.lastName;
    },
    set(value) {
      const arr = value.split('-');
      this.firstName = arr[0];
      this.lastName = arr[1];
    }
  }
}

简写形式(只读情况):

javascript

复制下载

computed: {
  fullName() {
    return this.firstName + '-' + this.lastName;
  }
}

3. 使用场景

  • 需要基于现有数据计算新值
  • 需要缓存计算结果以提高性能时
  • 模板中需要简洁表达复杂逻辑

二、监听器(Watch)

1. 基本概念

监听器用于观察和响应 Vue 实例上的数据变化,当被监听的数据发生变化时,执行指定的回调函数。

2. 核心特性

基本监听

javascript

复制下载

watch: {
  isHot: {
    handler(newValue, oldValue) {
      console.log('isHot被修改', newValue, oldValue);
    },
    immediate: true // 初始化时立即执行
  }
}

深度监听

javascript

复制下载

watch: {
  number: {
    handler() {
      console.log('number被修改');
    },
    deep: true // 监听对象内部属性的变化
  }
}

监听对象特定属性

javascript

复制下载

watch: {
  'number.a': {
    handler() {
      console.log('number.a被修改');
    }
  }
}

简写形式

javascript

复制下载

watch: {
  isHot(newValue, oldValue) {
    console.log('isHot被修改', newValue, oldValue);
  }
}

3. 使用场景

  • 需要在数据变化时执行异步操作
  • 需要监听数据变化并执行复杂业务逻辑
  • 需要在数据变化时执行副作用操作

三、computed 与 watch 的核心区别

1. 设计目的不同

  • computed:用于声明式地描述依赖关系,生成派生数据
  • watch:用于命令式地响应数据变化,执行特定操作

2. 缓存机制

  • computed:有缓存,依赖不变时直接返回缓存值
  • watch:无缓存,每次变化都执行回调

3. 异步支持

computed能完成的功能,watch都能完成 watch能完成的功能,computed不一定能完成,比如:watch能进行异步操作

  • computed:不能执行异步操作,必须是同步的
  • watch:可以执行异步操作

javascript

复制下载

// watch 支持异步操作
watch: {
  firstName(val) {
    setTimeout(() => {
      this.fullName = val + '-' + this.lastName;
    }, 1000)
  }
}

4. 返回值

  • computed:必须返回一个值
  • watch:没有返回值要求

5. 代码风格

  • computed:更声明式,关注"是什么"
  • watch:更命令式,关注"做什么"

四、性能对比

methods vs computed

javascript

复制下载

// methods:每次重新渲染都会执行
姓名: <span>{{fullName()}}</span>

// computed:依赖不变时使用缓存
姓名: <span>{{fullName}}</span>

五、使用原则

1. 选择 computed 当:

  • 需要基于其他属性计算新值
  • 需要缓存计算结果
  • 逻辑相对简单且同步

2. 选择 watch 当:

  • 需要在数据变化时执行异步操作
  • 需要执行副作用(如 API 调用、DOM 操作)
  • 需要监听变化并执行复杂逻辑

3. this 指向注意事项

javascript

复制下载

// Vue 管理的函数用普通函数
methods: {
  changeWeather() {
    this.isHot = !this.isHot // this 指向 Vue 实例
  }
}

// 非 Vue 管理的函数(定时器、Promise 等)用箭头函数
watch: {
  firstName(val) {
    setTimeout(() => {
      this.fullName = val + '-' + this.lastName; // 箭头函数保持 this 指向
    }, 1000)
  }
}

六、实际应用建议

  1. 优先使用 computed:当计算逻辑简单且需要缓存时
  2. 复杂响应逻辑用 watch:当需要执行异步或复杂操作时
  3. 避免过度使用 watch:能用 computed 实现的功能尽量用 computed
  4. 合理使用深度监听:根据数据结构决定是否使用 deep: true

总结

计算属性和监听器都是 Vue 响应式系统的核心组成部分,它们各有优势和适用场景。理解两者的本质区别和适用场景,能够帮助我们写出更高效、更易维护的 Vue 代码。在实际开发中,应根据具体需求选择最合适的工具,有时也会组合使用两者以达到最佳效果。

深度思考联网搜索