最近一直在优化项目的代码,在思考使用函数式编程来简化,有很多人问函数式编程到底是什么?函数式编程和面向对象的区别是什么?什么才是函数式编程的最佳实践. 为什么函数式编程概念很难理解?
本文就讲讲,如何快速理解并在项目中实际应用函数式编程.
为什么我们无法在解决实际编程过程中,更好的使用函数式编程的原因,是因为我们没有对函数式编程定义有很好的理解,很多文章对函数式编程下定义过于抽象,另外一个很重要的原因是因为大多数的资料只是简单的介绍函数式的api 方法,但并没有展示出在实际项目中如何灵活的应用.
我们先不给函数式编程下定义,如何更好的理解函数式编程,以及更好的实践,我们列出了以下的方案.
1、 函数式编程的举例降低认识成本.
2、函数式编程的基本概念.
3、函数式编程对项目的实际重构.
4、对函数式编程下定义.
1.函数式编程的举例降低认识成本
我们从一个的例子开始。下面是一个海鸥程序,鸟群合并则变成了一个更大的 鸟群,繁殖则增加了鸟群的数量,增加的数量就是它们繁殖出来的海鸥的数量。注 意这个程序并不是面向对象的良好实践,它只是强调当前这种变量赋值方式的一些弊端。
var Flock = function(n){
this.seagulls = n;
}
Flock.prototype.conjoin=function(other){
console.log('conjoin this',this);
console.log('conjoin other.seagulls',other.seagulls);
this.seagulls += other.seagulls;
return this;
}
Flock.prototype.breed = function(other){
console.log('this',this);
console.log('other.seagulls',other.seagulls);
this.seagulls = this.seagulls * other.seagulls;
return this;
}
var flock_a = new Flock(4);
var flock_b = new Flock(2);
var flock_c = new Flock(0);
var result = flock_a.conjoin(flock_c).breed(flock_b)
.conjoin(flock_a.breed(flock_b)).seagulls;
console.log('result',result);
代码的内部可变状态非常难以追踪,而且最终的答案还是错的,正确答案是16.
换一种函数式的写法:
var conjoin = function(flock_x,flock_y){
return flock_x + flock_y;
}
var breed = function(flock_x,flock_y){
return flock_x * flock_y;
}
var flock_a = 4;
var flock_b = 2;
var flock_c = 0;
var result = conjoin(breed(flock_b,conjoin(flock_a,flock_c)),
breed(flock_a,flock_b));
console.log('result',result);
这次我们得到了正确的答案,而且少写了很多代码.
函数式编程的基本概念.
一、纯函数
什么是纯函数
- 如果函数的调用参数相同,则永远返回相同的结果。它不依赖于程序执行期间函数外部任何状态或数据的变化,必须只依赖于其输入参数。
- 该函数不会产生任何可观察的副作用,例如网络请求,输入和输出设备或数据突变(mutation)。
这就是纯的函数。 如果一个函数符合上述 2 个要求,它就是纯函数。 你可能在过去甚至无意地情况下编写过纯函数。
在我们研究一个函数一个纯或不纯之前,让我们先讨论一下可怕的“副作用”。
举例:
纯函数的例子
function priceAfterTax(productPrice){
return (productPrice * 0.20) + productPrice
}
这个函数符合纯函数的定义。不依赖于任何外部的输入,不改变任何外部数据,没有副作用.
非纯函数:
var tax = 20;
function calculateTax(productPrice){
return (productPrice * tax/100) + productPrice
}
其中函数的计算结果取决于外部tax 变量, 而纯函数不能依赖外部变量。它没有满足第一个要求,因此这个函数不纯.
为什么说纯函数在Javascript 很重要?
纯函数在函数式编程中被大量使用。而且诸如 ReactJs 和 Redux 等优质的库都需要使用纯函数。
不过,纯函数也可以用在平常的 JavaScript 开发中使用,不一定要限死在某个编程范例中。 你可以混合纯的和不纯的函数,这完全没问题。
并非所有函数都需要是纯的。 例如,操作 DOM 的按钮按下的事件处理程序就不适合纯函数。 不过,这种事件处理函数可以调用其他纯函数来处理,以此减少项目中不纯函数的数量。
可测性和重构
另一个使用纯函数的原因是测试以及重构。
使用纯函数的一个主要好处是它们可以直接测。 如果传入相同的参数,它们将始终产生相同的结果。
同时纯函数还使得维护和重构代码变得更加容易。你可以放心地重构一个纯函数,不必操心没注意到的副作用搞乱了整个应用而导致终调试地狱。(如果项目中充斥着副作用,那么函数/模块之间的逻辑可能互相交织耦合,在后期新增逻辑时可能由于依赖复杂而难以重构,更常见的是开发为了应付需求而不断的引入新的副作用到原本的逻辑上从而导致代码变得越来越糟糕。)
正确地使用纯函数可以产生更加高质量的代码。并且也是一种更加干净的编码方式。
期待下一篇讲介绍函数式编程的其他概念:
- 可缓存性.
- 合理性
- 柯里化
- 代码组合