1、面试题:computed 和 watch 之间的区别
- computed 就是计算属性的意思,watch 就是监听的意思
- computed:
- 在调用 computed 是用来计算一个值的,在调用这个值时不需要加括号,如
{{displayName}},能够像属性一样使用 - 根据依赖的数据显示新的计算结果,同时计算结果会自动缓存,如果以来的数据没有变化,那么 computed 就不会重新调用方法
- 在调用 computed 是用来计算一个值的,在调用这个值时不需要加括号,如
- watch:
- 果某个数据或者属性变化了,就去执行某个函数,就像是一个 data 的数据监听回调,当监听的 data 数据变化时,执行回调
- watch 有两种选项,分别是
immediate和deepimmediate:true,表示”在第一次渲染时调用函数“deep:true,”在监听一个对象时,如 obj ,监听该对象里面的属性的变化,如 obj.a,这样的结果是:obj.a 变化时,也会判定 obj 也变化了
- 如果一个数据依赖于其他数据,那么这个数据设计为 computed
- 如果需要在某个数据变化时去执行某些事情,就是用 watch 来作为观察
# 2、computed - 计算属性
- 被计算出来的属性就是 计算属性
- 示例:
data: {
user: {
email: "fangyinghang@qq.com",
nickname: "方方",
phone: "13812312312"
}
},
computed: {
displayName: {
get() {
const user = this.user;
return user.nickname || user.email || user.phone;
},
set(value) {
console.log(value);
this.user.nickname = value;
}
}
},
template: `
<div>
{{displayName}}
<div>
{{displayName}}
<button @click="add">set</button>
</div>
</div>
`,
- 缓存:
- 如果依赖的属性没有变化,就不会重新计算
- getter / setter 默认不会做缓存,Vue 做了特殊处理
- 示例:
computed: {
displayUsers() {
console.log('执行了一次')
const hash = {
male: "男",
female: "女"
};
const { users, gender } = this;
if (gender === "") {
return users;
} else if (typeof gender === "string") {
return users.filter(u => u.gender === hash[gender]);
} else {
throw new Error("gender 的值是意外的值");
}
}
},
//在重复点击按钮后,该函数只会执行一次,只会出现一次 log
3、watch - 侦听
- 当数据变化时,执行一个函数
- 示例:
new Vue({
data: {
n: 0,
history: [],
inUndoMode: false
},
watch: {
n(newValue, oldValue) {
if (!this.inUndoMode) {
this.history.push({ from: oldValue, to: newValue });
} else {
this.inUndoMode = true;
}
}
},
template: `
<div>
{{n}}
<hr />
<button @click="add1">+1</button>
<button @click="add2">+2</button>
<button @click="minus1">-1</button>
<button @click="minus2">-2</button>
<hr/>
<button @click="undo">撤销</button>
<hr/>
{{history}}
</div>
`,
methods: {
add1() {
this.n += 1;
},
add2() {
this.n += 2;
},
minus1() {
this.n -= 1;
},
minus2() {
this.n -= 2;
},
undo() {
const last = this.history.pop();
console.log(last);
const old = last.from;
this.n = old;
this.inUndoMode = true
this.$nextTick(()=>{
this.inUndoMode = false
},0)
},
},
}).$mount("#app");
- 其中
this.$nextTick(()=>{...},0)与setTimeout(()=>{},0)作用是相同的 immediate: true第一次渲染时,也触发 watch
4、何谓变化
- obj 原本是 {a:'a'},现在 obj = {a:'a'},那么请问:
- obj 变了吗?obj.a 变了吗?
- 答:obj 变了,obj.a 没有变
- 简单类型看值是否变化,复杂类型(对象)看地址
- 这其实就是 === 的规则
关于 deep:true
- 如果 obj.a 变化了,请问 obj 算不算也变了?
- 一般来说认为没有变化,因为 obj 是一个对象,对象的地址没有变化,自然 obj 也没有变
- 如果需要答案是“也变了”,那么就添加属性
deep:true - 示例:obj.a 变化,obj也变化
watch:{
obj:{
handler(){
console.log('obj 变化了')
},
deep:true,
},
},
- 如果需要的答案是“没有变”,那么就是用
deep:false - deep 的意思是,监听 object 的时候是否往深了看
5、watch 的用法
- 语法一:
watch:{
x1:()=>{}, //错误,千万不能使用箭头函数,这里的 this 是window全局对象
x2:function(newValue,oldValue){},
x3(){},
x4:[f1,f2], //x4 变化时会依次执行 f1 和 f2 函数
x5:'methodName', //在 methods 中的方法
x6:{
handler:fn,deep:true,immediate:true
},
'obj.a':function(){}
}
- 语法2:
vm.$watch('xxx',fn,{deep:true,immedite:true})
creaeted(){
this.$watch('n',function(){
console.log('监听 n 的变化,n 变化了')
}),{immediate:true,deep:true}
}