Vue 中的
computed和watch分别代表计算属性和侦查属性。计算属性需要在其内部定义,当依赖属性发生变化时,计算属性会随之变化。而且,计算属性具有缓存机制,只要依赖的数据不发生张变,就算函数被重复调用,计算属性也不会发生改变。侦查属性,它也是基于依赖来监听数据模块,在依赖的数据发生变化时,它会调用一个函数,并传入 oldValue 和 newValue 两个值,相对于计算属性,它更适合执行一些更复杂和具体的业务逻辑操作,它也支持异步操作,这是计算属性不具备的功能。
一、计算属性的缓存机制
计算属性值如果只有一个函数,那么它会默认为 getter 方法(当然,若有需求,可以再添加 setter 方法),但是 getter 方法并不具备缓存功能,缓存功能是 Vue 主动往 getter 方法中添加的。下面来阐述缓存机制的一种实现原理,但它并不代表是 Vue 源码的实现原理,具体代码如下所示:
let obj1 = {
姓: "高",
名: "圆圆",
get 姓名() {
console.log('将姓与名相加')
return this.姓 + this.名;
},
set 姓名(xxx){
this.姓 = xxx[0]
this.名 = xxx.slice(1)
},
age: 18
};
console.log(obj1.姓名)
console.log(obj1.姓名)
console.log(obj1.姓名)
console.log('----------------') // 精髓
// 缓存是啥?就是哈希表。
const cache = {} // {'高':{'圆圆': '高圆圆'}}
let obj2 = {
姓: "高",
名: "圆圆",
get 姓名() {
if(this.姓 in cache && this.名 in cache[this.姓]){
console.log('有缓存')
return cache[this.姓][this.名]
} // 有缓存后,不会再执行以下代码,相当于 Vue 中计算属性后的函数。
cache[this.姓] = cache[this.姓] || {} // 保底值
cache[this.姓][this.名] = this.姓 + this.名
console.log('将姓与名相加')
return cache[this.姓][this.名];
},
set 姓名(xxx){
this.姓 = xxx[0]
this.名 = xxx.slice(1)
},
age: 18
};
console.log(obj2.姓名)
console.log(obj2.姓名)
console.log(obj2.姓名)
二、侦听属性的 immediate:true 和 deep:true
侦听属性具有以下两个特性:
- 在页面一开始初始化时,watch 不会被触发,即 “第一次”不会被触发,只有后继数据改变时,watch 才会触发和监听。
- watch 主要通过监听数据的地址是否发生改变来监听数据模块,但是,当数据变得复杂,如一个对象里面嵌套多个对象时,当只改变子对象的地址,而父对象的地址不改变时,父对象就不会被 watch 监听到。
针对这两种情况,只需要在代码最后设置
immediate:true和deep:true即可,前者英文是立即的意思,即第一次加载也要执行;后者 deep 的意思是深入,即深入遍历所有元素,而不仅仅是父元素。
new Vue({
data: {
a: 1,
b: {
c: {
d: 5
}
}
},
watch: {
// 该回调将会在侦听开始之后被立即调用
a: {
handler: 'someMethod',
immediate: true
},
// 该回调会在任何被侦听的对象的 property 改变时被调用,不论其被嵌套多深
b: {
handler: function(val, oldVal) { /* ... */ },
deep: true
},
}
})