一、背景
项目中偶然遇到有人在computed中这样写代码:
computed: {
getName() {
return function () {
return "张三";
};
},
},
这段代码看似没什么毛病,实际上它违背了computed的设计初衷,computed设计的原因是为了简化模板中又长又臭的计算逻辑,使模板代码看上去更加简洁,容易维护,并且计算属性会基于响应式依赖进行缓存,从而优化性能。
二、计算属性介绍
关于计算属性官方的描述如下:
为什么说上面这段代码违背了computed的设计初衷呢?
先来看看computed和methods的区别,然后我们就可以解释这个问题了,官方描述如下:
也就是说虽然它们俩的效果相同,但computed会基于响应式依赖进行缓存,methods不会,我们来验证一下:
三、实践检验
首先创建computed和methods,打印日志,然后在页面上分别调用几次
<template>
<div>
<p>{{ computed_getName }}</p>
<p>{{ computed_getName }}</p>
<p>{{ computed_getName }}</p>
<p>{{ computed_getName }}</p>
<p>{{ method_getName() }}</p>
<p>{{ method_getName() }}</p>
<p>{{ method_getName() }}</p>
<p>{{ method_getName() }}</p>
</div>
</template>
<script>
export default {
computed: {
computed_getName() {
console.log("computed计算属性被调用了");
return "张三";
},
},
methods: {
method_getName() {
console.log("methods方法被调用了");
return "李四";
},
},
};
</script>
页面运行结果如下:
控制台输出结果如下:
结果可以看到虽然计算属性computed_getName与方法method_getName都在模板中引用了4次,但是computed_getName只被触发了1次,而method_getName方法被触发了4次,也就验证了computed具有缓存功能的特性。
如果将计算属性改一下,换成开头所说的return函数呢?
<template>
<div>
<!-- 相应的调用计算属性也要改成函数的形式 -->
<p>{{ computed_getName() }}</p>
<p>{{ computed_getName() }}</p>
<p>{{ computed_getName() }}</p>
<p>{{ computed_getName() }}</p>
<p>{{ method_getName() }}</p>
<p>{{ method_getName() }}</p>
<p>{{ method_getName() }}</p>
<p>{{ method_getName() }}</p>
</div>
</template>
<script>
export default {
computed: {
computed_getName() {
// 修改成return函数的形式
return function () {
console.log("computed计算属性被调用了");
return "张三";
};
},
},
methods: {
method_getName() {
console.log("methods方法被调用了");
return "李四";
},
},
};
</script>
页面运行结果如下:
控制台输出结果如下:
结果很明显,return函数之后,想要拿到计算结果必须要调用这个计算函数(等同于调用方法,只不过定义方法的位置放在了computed中),也就失去了缓存的作用,再来品Vue官方文档:
我们为什么需要缓存?假设我们有一个性能开销比较大的计算属性 A,它需要遍历一个巨大的数组并做大量的计算。然后我们可能有其他的计算属性依赖于 A。如果没有缓存,我们将不可避免的多次执行 A 的 getter!如果你不希望有缓存,请用方法来替代。
那么,假设本例中的getName是一个开销较大的计算属性,现在它又失去了缓存的作用,我们是不是可以遵循官方约定使用方法来代替呢?
再有另一点原因是,一个计算属性的创建步骤比较复杂,有兴趣可参考如下文章进行学习(比较懒,有现成的就贴这了,轻点喷…):
而一个方法的创建就比较简单了,源码如下:
去掉这一大堆的容错判断,实际上就只是遍历所有的methods然后挂载到实例vm上,如下:
function initMethods (vm, methods) {
var props = vm.$options.props;
for (var key in methods) {
// 省略其他代码
vm[key] = typeof methods[key] !== 'function' ? noop : bind(methods[key], vm);
}
}
有的时候计算需要依赖模板数据中的某个状态,你们想通过计算属性中返回一个函数进行传参,既能借助computed缓存的特性来优化内存使用,又能简化模板中大量的计算逻辑,但想法虽好,还需理性认识computed。
因此,如果你还看到有人在computed中return函数的骚操作,你知道该怎么做了吗?
四、总结
- 计算属性适合简化模板逻辑,具备缓存特性,用得好绝对是神器
- 在计算属性中return函数的作用与method是一致的,但是性能开销远远高于method
共同学习,写下你的评论
评论加载中...
作者其他优质文章