博客基于vue2.x版本,主要对vue中计算属性computed,进行解析
前言:mthods和computed有什么区别?
总所周知,vue中计算属性是带有缓存的,而且很多人会将computed和method进行比较,诸如method没有缓存啊之类的。这里我通过自己的理解进行一个稍微全面的阐述。
浅显的回答
比较浅显的回答诸如下:
1. 在使用时,computed当做属性使用,而methods则当做方法调用
2. computed可以具有getter和setter,因此可以赋值,而methods不行
3. computed无法接收多个参数,而methods可以
4. computed具有缓存,而methods没有
上述回答都是比较浅层次的,当然也没有错,不过那只是表面现象,若要深究其理还需要阅读源码才能懂得起,这里我就不带入源码了(其实我也还没阅读源码)
所以这里稍微做一个比较深入但又不那么深入的理解。
深入的回答
vue对methods中的属性怎么处理的呢?
vue对methods就比较简单粗暴了,只需要遍历vue配置中的每一个属性,将其赋值到vue实例上,并使用bind进行函数中上下文对象的绑定
vue对computed中的属性怎么处理的呢?
vue对computed处理就比较复杂,这里引入几个核心属性:
Watcher:监听器,在响应式数据(data)的setter和getter中均有涉及,在setter中用于执行watcher,做到视图依赖该数据的视图更新;在getter中用于产生watcher,记录当前视图和数据的依赖关系
dirty:用来确认当前计算属性是否是脏数据(即已过期),当计算属性所依赖的数据发生改变时(运行setter),对于计算属性的watcher仅做一件事,即将当前计算属性的dirty改为true,标记为已过期
lazy:当前watcher是否立即执行,在当前实例组件中watcher的该属性是true,在计算属性的watcher中该属性是false
value:当前计算属性的值
我们可以先来看一个输出,代码如下:
<template>
<div>
<span v-if="showName">{{fullName}}</span>
<button @click="showName=false, count += 1">click</button>
</div>
</template>
<script>
export default {
data() {
return {
firstName: "zhang",
lastName: "san",
showName: true,
count: 0
}
},
computed: {
fullName() {
console.log("computed function invoked");
return this.firstName + this.lastName;
}
},
mounted() {
console.log(this);
}
}
</script>
输出如下:
下面截图能够很清楚的看到当使用计算属性时,组件实例中属性_watchers有两个warcher对象,一个是计算属性的,一个是组件实例的,前者lazy属性为true,后者为false,前者dirty为false,因为这个时候计算属性所依赖的数据还未发生改变。
除此之外,vue在收集watcher的时候,会将计算属性watcher也放入组件实例的,由于组件实例中的那个watcher和_computedWatchers对应的watcher是同一个引用,所以当计算属性的watcher改变时,组件实例的watcher也会改变。
当我们改变计算属性所依赖的数据(调用setter)时,vue会去通知该数据所对应的所有watcher执行一遍更新流程,而计算属性的更新流程就是简简单单地改变dirty为true,使得当前计算属性的值过期。
在watcher执行完之后,组件进入渲染流程(render),根据数据重新去渲染视图时(vue的diff算法),组件实例和计算属性的watcher会去重新收集依赖(getter),这个时候如果发现dirty已经为true,即已过期,那么就会重新去计算计算属性的值并返回,达到计算属性更新的目的
在上述例子中,点击按钮为什么不会再次console呢
至于例子中,点击按钮无法console,原理其实也很简单,因为dom都没有渲染,没有触发计算属性的getter方法,即便dirty变为了true,由于计算属性的watcher中lazy是true,是延迟执行的,所以也就不会输出console(实际上计算属性已经改变了,只是视图中没有用到而已)