函数式编程之美
编写程序的方法有很多种,或许你已经将程序设计得像一系列命令一样,这就是我们所说的“命令式编程”。又或许,你的程序将事物保存在对象中,并与它们交互,来回发送消息,这就是“面向对象编程”。但今天我要讲的是函数式编程。正如其他人提到的,函数式编程是一种编码风格,它与是否放置、;
是否放在{}
表达式之后或之后无关,而是与我们如何指示程序执行操作无关。从技术角度来说,这是一种“编程范式”。那么,你为什么要关注它呢?
有趣的功能✨
当我们谈论函数式编程的世界时,一切都是函数。这个概念和我们在学校学习的数学概念太相似了,老师会说这样的话:
函数是值之间的一种特殊关系:它的每个输入值都会返回一个输出值。
这个定义非常重要,因为它为我们提供了程序的基础,即纯函数。纯函数是指只依赖于输入的函数,它们不会寻找你世界之外的任何东西,只接收你传入的参数,并且只返回输出,不会影响世界的其他部分。例如,看到这些函数,你能说出第一个函数有什么问题吗?
第一个版本❌
let age = 19
function getMyAge() {
console.log(`I'm ${age} years old.`)
}
getMyAge(age)
age = 20
getMyAge(age)
第二版✅
function getMyAge(age) {
return `I'm ${age} years old.`
}
getMyAge(19)
getMyAge(20)
在第一种情况下,函数会查找作用域之外的变量,从而以某种方式改变世界。在这种情况下,理想的情况是只返回值,正如你所注意到的,如果我们使用相同的参数(即使没有参数)调用该函数,我们得到的值也会不同。在纯函数中,这种情况不会发生。
现在,你已经对函数式编程的优点有了基本的了解,但我们还有更多功能,请查看下面的内容💪。
副作用🌊
副作用是在计算过程中与外界发生的任何交互,使用纯函数不会发生这种交互,而且我们的代码可以更加可预测,因为我们的结果仅取决于它的输入,如果我们知道函数是什么样子,以及它接收哪些输入,您就可以预测结果。
可变性🐺
可变性指的是事物可以改变,但在函数式编程中,不鼓励使用可变性。当我们拥有不可变数据时,其状态在创建后就无法更改。如果需要更改某些内容,则需要创建一个新的值。
可变示例
function changeFirstElem(array) {
array[0] = 'Lose yourself to dance'
}
const daftPunkPopSongs = ['Instant Crush', 'Get Lucky', 'One More Time']
changeFirstElem(daftPunkPopSongs)
不可变示例
function changeFirstElem(array) {
const modifiedArray = ['Lose yourself to dance', ...array]
return modifiedArray
}
const daftPunkPopSongs = ['Instant Crush', 'Get Lucky', 'One More Time']
const modifiedArray = changeFirstElem(daftPunkPopSongs)
这太棒了,因为我们让事情变得更安全了,代码中引入 bug 的几率也更大了,也意味着测试/调试代码也更容易了。因为我们只需要了解输出,遵循参数,如果输出错误,我们就能确定问题出在函数本身,而不是随机交互。
递归🥞
递归是一种技术,我们可以将问题分成小块来解决问题,这有助于我们在使用交互时避免一些副作用。
function myCount(int i) {
if(i >= 10) return 0
else return i + myCount(i+1)
}
myCount(1);
对我来说,递归使代码更具声明性、更易读和更清晰,尽管在许多情况下我更喜欢使用迭代方式。
函数式编程的超级英雄们
除了递归之外,我们还有树函数来帮助我们操作数据,它们是map-filter-reducer。在 JS 中,函数也被视为值,因此我们可以将其作为参数传递给其他函数。
Map,给定一个数据集合,您可以传递一个函数来转换每个项目。
const numbers = [1, 2, 3];
const doubles = numbers.map(num => num * 2) //[2, 4, 6]
过滤器接收数据集合,您可以传递返回集合子集的条件函数。
const numbers = [1, 2, 3];
const isGreaterThanOne = numbers.filter(num => num > 1) //[2, 3]
最后,Reduce,给定一个数据集合,你可以将其简化为单个值。
const numbers = [1, 2, 3];
const mySum = numbers.reduce((accumulator, num) => accumulator + num) //6
结论💃
我刚开始学习函数式编程,这些事情激励着我不断学习,也让我不断查阅各种资源。当然,函数式编程也有弱点,但这不是重点。如果你需要其他资源,我下面会提供一些,尽情享受吧!
图书
Hackernoon - 理解函数式编程
Frisby 教授撰写的《函数式编程基本指南》
Jichao Ouyang 撰写的函数式 JavaScript 迷你书
实用函数 Javascript 在线书籍
会谈
Anjana Vankil - 函数式编程:是什么?为什么?怎么做?我的最爱之一
Anjana Vankil - 函数式 JS 的不可变数据结构
趣味函数系列