一句话重点:函数式好处多多,但是不要过度追求函数式。

什么是函数式编程

函数式编程是一种_编程范式_,也就是编写代码指令的方式相对应的还有过程式编程和面向对象编程,函数式并不是某一编程语言的专属,现在的多数主流语言都是多范式,或多或少的都支持一些函数式的特性作为前端程序员,应该对于函数式并不陌生,毕竟我们总是在用到函数式的一些特性。只是有可能我们并不知道它和函数式的关系。例如`[1,2,3,4].map(x => x + 1)`就是一个最简单的函数式的范例,之所以说它是函数式的,是因为它使用到了高阶函数。数据不变等特性

什么不是函数式编程

是否是函数式并不是一件非黑即白的事情,浅红色是红色,深红色也是红色。同样的,有的代码用到的函数式特性少一些,有的用到的函数式特性多一些。只要有用到,就是函数式的。同时呢,一段代码既可以是面向对象的,也可以是函数式的。这个是不冲突的。 `[1,2,3,4].map(x => x + 1)`中使用的map就是Array对象上面的一个方法,所以这一段代码也是面向对象的所以,我们要抛弃一种不好的想法,看见自己的代码或者别人的代码,便去批判够不够函数式。编程范式是为了更好的思考问题和解决问题,只要能做到这一点,什么编程范式很重要么?

函数式能干什么

函数组合及复用

这是函数式的基本功能之一,可以使用不同的方式来组合已有的函数。由于函数式编程中的函数都是无状态无副作用的纯函数,所以可以被用在任何地方,不会产生意料之外的效果

所定义即所得

由于函数式中的数据不可变性的特点,一个数据在被定义的时候是什么,以后还会是什么,不会因为他被别的函数调用过就会变心。

声明式编程,代码可读性高

函数式可以用比较接近自然语言的方式来描述自己需要一个什么样的东西,例如

arr.map(x => x + 2)
    .filter(x => x < 4)
    .map(x => x * 2)

我们可以很清晰的看出来上面一段代码的意图,对一个数组每个元素进行+2的操作,然后过滤出小于4的元素,最后对每个元素\*2 重点是告诉程序我_要什么_,而不是一步步的告诉程序_怎么做_

对于计算结构的抽象

var sum = (acc, x) => acc + x;
arr.reduce(sum, 0)

reduce是针对数组的一个累加器的计算结构,而sum是具体的累加逻辑。这个计算结构是抽象后的固定形式,而具体累加逻辑可以在具体使用时使用不同的逻辑。

函数式不能干什么

函数式不是银弹,不适用所有的场景。

  • 比如对于异步的操作就比非函数式要复杂
  • 由于每次都返回新的数据,所以对于大数组会很费内存,会不断的触发gc
  • 由于js中没有惰性计算,所以一个数组的反复map和filter实际上会循环很多次,不如命令式里面的一个for循环速度快
  • 由于多是函数调用,对于debug会稍微复杂一点

如何看待函数式

  • 不要追求绝对的函数式编程,这样会过犹不及
  • 根据当前的自身需求,来采用相匹配的函数式特性
    • 例如感觉写一堆for循环,时间久了自己都不太清楚用这个循环做了啥,可以用map/reduce/filter等数组操作函数
    • 如果总是写一些很相似的功能,例如把函数拆分耕细粒度的小函数,通过函数组合的方式来构造新函数。 例如pipe(map(take(2), add(1)))表示取出数组前两个元素,并且加1的操作,不需要单独写一个函数,使用已有的两个函数take和add就可以组成想要的功能
  • 可以学习一些理论性的知识,看透函数式的本质。这样就可以做到无招胜有招了。

后面还有什么

  • 函数式的特性
  • 函数式类库的使用
  • 函数式背后的一些理论
  • 函数式和异步操作的结合