函数式编程入门(1)
因为es6
的一些新特性,感觉是有点函数式编程
的味道,所以也是了解了一波有关的东西吧,顺便记录下来,做个入门教程
(哪里有错的话还希望大家留言指正=-=)
什么是函数式编程
,为什么要函数式
?
这个问题也许更应该去看什么知乎大佬之类的回答吧。我仅从自己看书包括写代码的理解来看,首先函数式
是相对于命令式
的吧。比如在es6
之前,你要遍历一个数组的话,可能得像下面这样
var arr = [1,2,3];
for (var i = 0, length = arr.length; i < length; i++) {
// do something...
}
但是大家也都知道,在es6
之中,我们可以这样
var arr = [1, 2, 3];
arr.forEach(el => {
// do something
})
简单的说这些也许并不能让你感受到函数式
的魅力,但是想想,如果项目不断复杂,按照以往那样的命令式
的写法,对于复杂结构甚至要好几层的for
循环去拿索引,这对于后期维护来说是很操蛋的一件事情。哪怕是你自己写的代码,过几个月再来看一遍,也不得不跟着嵌套的for
循环去捋逻辑,从而判断这代码究竟是想实现怎样的一个功能。而这些,实际上是可以通过封装一些简单易用的函数去实现的,通过良好的命名(比如es6
的filter
),使得代码具有良好的可读性,我们可以仅仅通过看到函数的名字,就知道这里想干嘛,而不需要去过分关注具体的细节。而这仅仅是函数式
带来的好处的一小部分,即良好的可读性
和易维护
性。其他更多的好处我相信在后续的章节中大家会感受的比较深(如果不鸽的话#雾)
结束之前说一点更干的东西—闭包
为什么说的是闭包呢?(当然是有用了,呸!),闭包的概念对于函数式而言我觉得是相当重要的吧,很多高阶函数的实现,都依赖闭包。下面一个很常见的代码(?也许不是那么常见)
const cacheFn = (fn) => {
const cache = {}; // 设置缓存
return (number) => cache[number] || (cache[number] = fn(number))
}
const calculation = (number) => {
if (number === 0) {
return 1;
}
console.log(number)
return number * factorial(number - 1); // 递归
}
const factorial = cacheFn(calculation)
factorial(3);
console.log('---------------------');
factorial(5);
运行结果如下:
简单说一下这段代码,这就是一个简单的求阶乘,相信大家也都做过(maybe用C),factorial
是用来获取阶乘结果的函数,cacheFn
是用来设置缓存的函数,calculation
是用来递归计算阶乘的函数。和以往不同的是,我们不再是直接运行calculation
,而是运行经由cacheFn
包装返回的函数factorial
cacheFn
在运行之后会返回一个函数,并且闭包一个变量cache
,之后的每次计算都会先查看cache
中是否已经有了相关的结果,才会去判断是否要执行calculation
这个函数。而这个cache
变量是只有cacheFn
内部可以访问的,外部访问不到[1]。虽然这个例子很简单,但是仔细看你会发现,上面涉及到的几个函数,都是纯函数
[2],这使得我们可以大胆的嵌套这几个函数,而不用操心外部环境变化而带来的不确定性。
[1](因为
cacheFn
返回的函数中保留了对cache
的引用,所以在cacheFn
运行完毕之后,cache
这个变量的内存没有被js
的垃圾回收机制所回收,但是由于外部不存在这个变量的引用,所以这个变量实际上也就变成了内部的一个私有变量,这种感觉和java
/ts
啥的private
有点像吧,但是由于这个引用会一直存在,所以会导致cache
的内存一直处于被占用状态,也有可能导致内存泄漏
等问题,这就需要手动置空引用了。)
[2] 纯函数,指的是不依赖外部运行环境的函数(不对外部环境产生任何副作用,也不引用外部数据,所需要的数据全部从参数获取),严格来说甚至应该必须包含输入输出(标准的纯函数式语言比如haskell
是这样的-0-)。对于任何确定的参数,函数总是返回一个唯一确定且固定的值,这就像数学上对于函数的定义,对于任意一个给定的x,有且仅有一个与之相对应的y。wiki
有了闭包之后我们其实就可以做很多好玩的事情了,因为可以仅仅在内部保留一个变量,所以也可以很好地实现诸如洗牌算法
之类的了,或者像上面一样针对特定场景设置一个私有缓存类似的。
结?
哇,比想象中的累很多,看函数式
也有一段时间了,加上看rx
之类的,真的是越发喜欢这种编程思想,所以想着开这么一坑给大家安利一波,但是的确很累啊=-=。写这么点花了几个小时,查东西乱七八糟的。
当然了这仅仅也是第一篇,作为一个简单的介绍对于函数式编程
(尽管肯定还有很多没介绍到的地方,我尽力了- -),下一篇的话可能会更多的写一些代码了,介绍一下高阶函数
,以及什么柯里化
,偏函数
乱七八糟的(?如果还有下一篇的话,有也不知道啥时候=-=)