在 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)
}
}
六、实际应用建议
- 优先使用 computed:当计算逻辑简单且需要缓存时
- 复杂响应逻辑用 watch:当需要执行异步或复杂操作时
- 避免过度使用 watch:能用 computed 实现的功能尽量用 computed
- 合理使用深度监听:根据数据结构决定是否使用
deep: true
总结
计算属性和监听器都是 Vue 响应式系统的核心组成部分,它们各有优势和适用场景。理解两者的本质区别和适用场景,能够帮助我们写出更高效、更易维护的 Vue 代码。在实际开发中,应根据具体需求选择最合适的工具,有时也会组合使用两者以达到最佳效果。
深度思考联网搜索