大家好,这里是大家的林语冰。
我再重申一遍,计算属性(computed properties)绝对是 Vue 最重要的功能。
当然啦,作用域插槽(scoped slots)允许我们创建某些优雅的抽象,并且侦听器(watcher)也有其用武之地。
但私以为没有什么功能可以和计算属性的价值势均力敌。我这么认为主要出于下述两个原因:
- 计算属性允许我们编写更多声明式代码
- 声明式代码是更好的代码
由于这一切原因都与声明式代码有关,因此让我们花一些时间来了解声明式代码到底是什么鬼物。
本期共享的是:
- 声明式代码是什么鬼物,以及它与命令式代码有何不同
- 哪怕我们不知道声明式代码是什么,我们也会爱上声明式代码
- 计算属性如何允许我们编写更多的声明式代码
- 为什么编写声明式代码如此重要
免责声明
本文属于是语冰的直男翻译了属于是,略有删改,仅供粉丝参考。英文原味版请传送 The Most Important Feature in Vue。
声明式代码是什么鬼物?
计算机编程最常见的方法是给它一个指令列表。然后计算机将循序渐进地执行每条指令,直到程序完成。这被称为"命令式编程"(imperative programming)。
整个编码过程就像我们正在向从未做过饭的家伙解释我们最喜欢的料理食谱。
我们不能只告诉它们酱汁的成分,然后就期望它们可以完成五星级美食。它们需要尽可能详细地了解料理的每个步骤。如果我们遗漏任何细节,它们可能会犯错误并做出"黑暗料理"。
js
const food = ['apple', 'banana', '...']
for (let i = 0; i < food.length; i++) {
handleFood(food[i])
}
// 其他具体步骤......
但是,如果我们面向有烹饪经验的大厨解释这个食谱,那又该怎么办呢?
我们不再需要指定如何完成每一个料理步骤,因为大厨已经有对应的知识储备。我们所需要做的就是告诉它们需要做什么。
这被称为"声明式编程"(declarative programming)。
我们无需指定程序的每一个步骤,只需告诉计算机应该去执行什么任务,它就知道如何处理其余的事情。
js
const food = ['apple', 'banana', '...']
cook(food)
这就是社区如此青睐 Vue 的原因
我们和许多其他 Vue 爱好者青睐 Vue 的根本原因在于,Vue 天然遵循这种确切的声明式方案。
如果我们使用 v-for
编写模板,那就无需像命令式编程那样编写任何循环遍历数组,并向 DOM 添加新元素的逻辑。
我们无需纠结该数组更改时会发生什么。我们不必担心如何逐个元素地浏览 DOM 并更新它们,从而确保它们与数据同步。
Vue 为我们做了这一切,我们只需使用 v-for
就欧了。我们只需要告诉 Vue,我们想要它去执行什么指令或任务。
声明式编程一个极其强大和解放生产力的概念,它使开发变得更加简单和容易!我们希望尽可能多地利用声明式编程,并将尽可能多地把代码编写为声明式代码,而不是命令式代码。
计算属性就是这样做的。
计算属性允许我们编写声明式代码
假设我们这里有一个组件,它接受 list
属性,但始终只渲染前 3
个元素:
js
export default {
props: {
list: {
type: Array
}
},
data() {
return {
topThree: []
}
},
watch: {
list: {
immediate: true, // 组件加载后立即运行
handler() {
// 重新计算并设置 topThree 变量
this.topThree = this.getTopThree(this.list)
}
}
},
methods: {
getTopThree(list) {
list.sort() // 数组排序
return list.slice(2) // 返回前 3 个元素
}
}
}
无论 list
属性如何变化,我们的组件状态 topThree
将始终包含列表中的前三个元素。
抽丝剥茧,这就是上述代码的分步拆解:
- 如果
list
属性发生变化,我们的侦听器就会触发 - 我们将
this.list
传递给getTopThree
方法来计算前 3 个元素 - 我们获取这些元素,并更新我们的组件状态
上述代码中,我们遵循的命令式编程,准确指定需要实现的功能。
实际上,我们的侦听器在某种程度上是声明式的,因为我们不需要编写任何逻辑来检查 props
何时更新。当且仅当 list
属性发生变化时,Vue 会为我们运行该函数。
但如果我们将代码重构为计算属性,我们最终会得到一种更具声明式的方案。我们还会发现,这是一种更简单、更容易理解的方案,也可以实现同款功能。
声明式代码是更好的代码
要将上述代码重构为计算属性的声明式代码,我们首先要完全弃用侦听器:
js
export default {
props: {
list: {
type: Array
}
},
data() {
return {
topThree: []
}
},
methods: {
getTopThree(list) {
list.sort() // 数组排序
return list.slice(2) // 返回前 3 个元素
}
}
}
我们也可以删除 data
部分:
js
export default {
props: {
list: {
type: Array
}
},
methods: {
getTopThree(list) {
list.sort()
return list.slice(2)
}
}
}
现在我们可以将该方法转换为计算属性,我们将其命名为 topThree
:
js
export default {
props: {
list: {
type: Array
}
},
computed: {
topThree(list) {
list.sort()
return list.slice(2)
}
}
}
虽然但是,计算属性不能接受任意参数。相反,我们将直接从计算属性内部获取 list
属性:
js
export default {
props: {
list: {
type: Array
}
},
computed: {
topThree() {
// 拷贝 list,避免副作用
const copy = this.list.slice()
copy.sort()
return copy.slice(2)
}
}
}
改变数组时,我们必须首先拷贝 list
,这样我们就不会意外地修改它,并产生令人头大的副作用。
以下是我们通过这个示例就可以看到的若干好处:
- 更少的代码 ------ 我们的组件的代码行数显著减少
- 更精简 ------ 我们的组件中没有四个不同的部分:
props
、data
、侦听器和方法,我们只需要考虑两个部分:props
和计算属性 - 关注我们的目标 ------ 我们不会浪费时间编写代码来触发更新,这与我们尝试编写的功能无关。当某人试图阅读代码并理解其具体功能时,这一点尤其重要。
高潮总结
在本文中,我们深度学习了什么是声明式代码,并发现大家如此喜爱 Vue 的原因之一在于,Vue 允许我们以更具声明式的方案编写代码。
我们还看到计算属性是我们将命令式代码转换为声明式代码的主要方案,并看到以声明式风格编写代码的若干好处。
因此,在我看来,计算属性是 Vue 中最重要的功能。
本期话题是 ------ 你认为 Vue 那个功能比计算属性更重要?
欢迎在本文下方自由言论,文明共享。谢谢大家的点赞,掰掰~
《前端猫猫教》每日 9 点半更新,坚持阅读,自律打卡,每天一次,进步一点。