个人github github.com/zhuanyongxi…javascript
这多是一篇会被常常改动的文章,它记录了如今的我对函数式编程粗浅的理解。html
函数式编程并非github上面的一个工具库,它的年龄比JavaScript要大得多,它是一种通过了几十年,被众多计算机科学家证实了的行之有效的编程范式。它不是学会了几个函数式编程工具的API就能彻底掌握的,它更多的是编程思惟上的转变。具体一点的代码实例能够看《JavaScript函数式编程之pointfree与声明式编程》。java
那到底为何用使用函数式编程?git
若是总结成一个字,那就是为了“爽”。“爽”在哪?读和写。github
这可能会让你不觉得然,读和写对你来讲可能不是最重要的事情。不过以我当前的认知水平来看,设计模式、编程范式,甚至是编程语言自己,他们的最大意义都在于这两个字。编程
好比编程语言,它的落点在于“语言”,“语言”是用来干什么的?交流沟通。跟谁交流沟通?跟人,而非机器。咱们写的代码会通过层层编译,最终转化成0和1才能被计算机执行。那咱们为何要这么麻烦,而不直接用0和1编程?由于很差写也很差读。若是你手速足够快,大脑也足够发达,用0和1编程也是能够的。可那样的话,还须要计算机吗?虽然层层编译的过程,势必会下降效率,不过有摩尔定律来接盘,大可没必要担忧。设计模式
若是所有功能的实现只须要几行代码,大谈设计模式、编程范式就太矫情了。咱们之因此须要这些东西,是由于随着代码量的增多,代码的读写对咱们形成了困扰。数组
那函数式编程是如何解决这些问题的?编程语言
好比纯函数,它有不少优势,我的认为最重要的是:它明显的下降咱们的认知负荷。ide
从最普通的函数提及:
var a = 1;
function A(val) {
a = 2;
return a + val;
}
复制代码
这里的变量a就是被你们嗤之以鼻的全局变量。它很是容易致使出现bug,当代码量不少的时候,极可能会由于重名而被覆盖,从而致使其余使用了这个变量的程序出错。即使是正常的修改,当咱们再次使用函数A的时候,弄清变量a当前的状态也是十分的困难,这就使得函数A变得难以理解,难以理解的函数就得不到使用者的信任。
面向对象编程的“封装”在必定程度上解决了这个问题:
var obj = {
a: 1,
A: function(val) {
return this.a + val;
}
}
复制代码
封装了以后全局变量大大的减小了,即使有两个对象重名了,相对上面的状况,修改起来也不会有那么大的负担。但它并无完全解决这一问题,由于属性a是可变的,每次调用方法A的时候,弄清属性a的状态依然不容易。
而函数式编程不存在这个问题。在函数式编程中,使用可变的外部的变量是不被容许的。例如:
var a = 1; // 除了当作参数传入,使用变量a的函数都不是纯函数
function A(val) { // 不是纯函数
return a + val;
}
const b = 1;
const B = function(val) { // 纯函数
return b + val;
}
复制代码
随着代码量逐渐增多,这种写法的优点就愈发明显了,若是还能更进一步的减小耦合,那你就能够在很大程度上去“断章取义”,不去管上下文。每个纯函数咱们均可以充分信任,它的输出只与传进去的参数有关。
不只仅在函数式编程中,面向对象的编程一般也会建议写纯函数。
纯函数对代码的调试也有极大的好处,这也是函数式编程的优势之一:方便调试。
在初学函数式编程的时候,会很难理解这一点,由于当咱们使用纯函数帮咱们解决问题的时候,老是得不到想要的结果,尤为是在使用函数式的工具库进行函数组合的时候,断点调试都很困难,就算你把断点打到了第三方的工具库里面,你真的肯定你能在短期内看懂人家的源码吗?这个时候每每只能想办法去console.log
。不过这个问题是能够经过不断的学习总结来解决的。即使使用其余的方式编程,不熟悉所用的工具也会出现一样的状况,这并非函数式编程的问题。
绝大多数的bug都是由反作用引发的。也就是系统状态的变化。这一点没法经过学习来解决,你能记住成千上万个状态,并能时刻了解他们的变化吗?可若是咱们是在函数式编程,使用了大量的纯函数,因为纯函数不产生反作用,在调试的时候,咱们只须要去调试会产生反作用的部分就能够了。
在函数式编程中,一切的技巧的目的都是为了让你的代码更加的函数式。可掌握有些技巧的成本很高,这就致使部分人对函数式编程的”可读性“产生了质疑。
其实,函数式代码的可读性与读代码的人的函数式编程的能力有直接的关系。以下图:
命令式编程很符合人类的思惟习惯,入门的成本很低,而声明式的函数式编程的学习则有必定的门槛,对于新手来讲,可能几乎没有可读性。只有不断的深刻学习,这种可读性的优点才会逐渐的体现出来。这多是致使函数式编程没有被普遍应用的最主要缘由。
若是还要举的话。。。
面向对象编程更倾向于封装,而函数式编程更倾向于抽象。
面向对象编程抽象的结果是一个类,函数式编程抽象的结果是一个过程(一个函数)。
封装和抽象有什么区别?
他们并无明显的界限,抽象是经过封装来实现的,我找不到一个只是抽象而不是封装的例子。封装和抽象的目的略有不一样。简单的讲,封装只是把一些会再次使用的操做包起来,等待下次使用。抽象也会有“包起来”的动做,可它更多的目的在于要划清界限。这就比如让咱们解释一个概念,若是你说“我懂,但我就是说不出来”,那么大几率你是没有懂。咱们是否能清晰准确的说清楚,取决于咱们脑中对这一律念的界限是否划清楚了。若是没有划清楚,咱们就没办法下断语去说明它是什么和它不是什么。抽象也是如此,它须要咱们搞清楚它是干什么的,把不该该干的事情都去掉。“它是什么”这一点越明确,那么这一封装的抽象程度就越高。
参考资料: