(翻译)函数式编程之美

441 阅读4分钟

编写程序的方式有很多,可能你将程序写的看起来像一系列的命令,这就是所谓的“命令式编程”,或者你在编写程序时,把东西保存在对象中,并与它们进行交互,来回发送消息,这就是“面向对象编程”,但是今天我谈论的是函数式编程,就像刚才说的两种一样,函数式编程是一种代码风格,这不是在讨论要不要加;,或者{ }是放在表达式的后面还是下面的问题,而是我们如何指导程序去执行,在技术上这叫做“编程范式”。那么为什么要关心这个呢?

有趣的函数 ✨

当我们讨论函数式编程的世界时,一切都是函数。概念上非常像数学上的概念,就是当我们在学校时候,老师对我们说的那样:

函数式一种值与值之间的特殊关系:给定的每一个输入都有确定的输出。

这个定义是非常重要的,因为这是我们项目的基础,叫做纯函数,纯函数是这样的一种函数,它只依赖于它的输入,不依赖于外部的任何东西,期待你传递的参数,只返回输出,不会影响到其他地方,举个例子,下面的这些函数,一眼看上去你觉得有问题吗?

第一个版本 ❌

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,这意味着我们测试和调试代码变得更容易了。因为我们需要根据参数知道输出的情况,所以如果输出是错的,我们可以确定是我们的函数出了问题,而不是因为什么不确定的原因。

递归

img

递归是一种技术,让我们可以把一个问题分解成小块来解决,这有助于我们在和外界交互时避免一些副作用。

function myCount(int i) {
  if(i >= 10) return 0
  else return i + myCount(i+1)
}
myCount(1);

对我来说,递归使代码更易读,更简洁,在很多情况下我更喜欢使用迭代的方式。

函数式编程中的超级英雄🧚‍♀️

img

在递归之外,我们还有三种函数可以帮助我们处理数据,它们就是map-filter-reducer。在JS中,函数也可以被当做值,因此我们可以把函数当做参数传给其他函数。

Map,给定一组数据,你可以传递一个函数来对数组中的每一项进行映射转换。

const numbers = [1, 2, 3];
const doubles = numbers.map(num => num * 2) //[2, 4, 6]

Filter,接受一组数据,你可以传递一个条件函数并且返回筛选后的数据子集。

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 - Understanding Functional Programming Professor Frisby's Mostly Adequate Guide to Functional Programming Functional JavaScript Mini Book by Jichao Ouyang Pragmatic Function Javascript online book

论坛

Anjana Vankil - Functional Programming: What? Why? How?One of my favourites Anjana Vankil - Immutable data structures for functional JS Fun Fun Function Series

原文链接

The beauty of Functional Programming