# Computed 和 Watch
**Computed**本质是一个具备缓存的`watcher`,依赖的属性发生变化就会更新视图。
适用于计算比较消耗性能的计算场景。当表达式过于复杂时,在模板中放入过多逻辑会让模板难以维护,可以将复杂的逻辑放入计算属性中处理。
**Watch**没有缓存性,更多的是观察的作用,可以监听某些数据执行回调。当我们需要深度监听对象中的属性时,可以打开`deep:true`选项,这样便会对对象中的每一项进行监听。这样会带来性能问题,优化的话可以使用字符串形式监听,如果没有写到组件中,不要忘记使用`unWatch`手动注销哦。
- 功能上:`computed`是计算属性,也就是依赖其它的属性计算所得出最后的值。`watch`是去监听一个值的变化,然后执行相对应的函数
- 使用上:`computed`中的函数必须要用`return`返回;`watch`的回调里面会传入监听属性的新旧值,通过这两个值可以做一些特定的操作,不是必须要用`return`
- 性能上:`computed`中的函数所依赖的属性没有发生变化,那么调用当前的函数的时候会从缓存中读取,而`watch`在每次监听的值发生变化的时候都会执行回调
- 场景上
- computed:当一个属性受多个属性影响的时候,例子:购物车商品结算;
- watch:当一条数据影响多条数据的时候,例子:搜索框
## 使用场景
computed和watch都起到监听/依赖一个数据,并进行处理的作用
`computed`: 一个数据受多个数据影响,对同步数据的处理。
`watch`: 一个数据影响多个数据,观测某个值的变化去完成一段开销较大的复杂业务逻辑。
## computed
很多时候, 在页面调用接口加载数据之前, 可能会出现报错的情况, 但是页面不会有问题, 那么产生这个问题的原因, 是什么呢?
例如下面的代码, 属性值不存在, 所以就报错了
```html
<div>{{list.a.b}}</div>
<script>
var vm = new Vue({
el: '#demo',
data: {
list: {}
}
})
</script>
```
为了避免不报错, 这时候, 类似加个判断, 在数据多的情况下, 明显的优势就出来了
```html
<div>{{b}}</div>
<script>
var vm = new Vue({
el: '#demo',
data: {
list: {}
},
computed: {
b(){
if(!Object.value(this.list).length && this.list.a.b){
return this.list.a.b
}else{
return ''
}
}
}
})
</script>
```
## watch的高级用法
1. handler方法和immediate属性
```html
<div id="demo">{{ fullName }}</div>
<script>
var vm = new Vue({
el: '#demo',
data: {
firstName: 'Foo',
lastName: 'Bar',
fullName: 'Foo Bar'
},
watch: {
firstName: function (val) {
console.log('第一次没有执行~')
this.fullName = val + ' ' + this.lastName
}
}
})
</script>
```
可以看到,初始化的时候`watch`是不会执行的。看上边的例子,只要当`firstName`的值改变的时候才会执行监听计算。但如果想在第一次它在被绑定的时候就执行怎么办?
这时候就要修改一下我们的例子:
```js
var vm = new Vue({
watch: {
firstName: {
handler(val) {
console.log('第一次执行了~')
this.fullName = val + ' ' + this.lastName
},
// 代表在watch里声明了firstName这个方法之后立即先去执行handler方法
immediate: true
}
}
})
```
2. deep属性
`watch`里还有一个`deep`属性,代表是否开启深度监听,默认为`false`,下面来看一个例子:
```html
<div id="app">
<div>obj.a: {{obj.a}}</div>
<input type="text" v-model="obj.a">
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
obj: {
a: 1
}
},
watch: {
obj: {
handler(val) {
console.log('obj.a changed')
},
immediate: true
}
}
})
</script>
```
当我们在input输入框中输入数据改变`obj.a`的值时,我们发现在控制台没有打印出`'obj.a changed'`。
受现代 JavaScript 的限制 (以及废弃 Object.observe),Vue 不能检测到对象属性的添加或删除。
由于 Vue 会在初始化实例时对属性执行`getter/setter`转化过程,所以属性必须在`data`对象上存在才能让 Vue 转换它,才能让它是响应式的。
所以,想要深度监听属性值的变化,就需要`deep:true`了
```js
watch: {
obj: {
handler(val) {
console.log('obj.a changed')
},
immediate: true,
deep: true
}
}
```
`deep`属性的意思是深度遍历,会在对象一层层往下遍历,在每一层都加上监听器。
但是使用`deep`属性会给每一层都加上监听器,性能开销可能就会非常大了。这样我们可以用字符串的形式来优化:
```js
watch: {
'obj.a': {
handler(val) {
console.log('obj.a changed')
},
immediate: true
// deep: true
}
}
```
直到遇到`'obj.a'`属性,才会给该属性设置监听函数,提高性能。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理