作者:yanyige | 发布时间:2017-04-24 21:34
函数式编程
上次参加360前端星计划,被月影大大的JS进阶教程虐了一番之后,过程抽象这个概念就一直在我的脑中盘旋。“到底什么是过程抽象?” 月影老师提到,过程抽象是一种编程思路,我目前认为,过程抽象应该是函数式编程的一种。
在淘宝FED前端团队中一篇博客中提到:
函数式编程可以理解为,以函数作为主要载体的编程方式,用函数去拆解、抽象一般的表达式
说道用函数去拆解、抽象一般的表达式,在第一时间,我就想到了函数柯里化(currying)
函数柯里化(currying)
currying 又称部分求值。一个currying 的函数首先会接受一些参数,接受了这些参数之后, 该函数并不会立即求值,而是继续返回另外一个函数,刚才传入的参数在函数形成的闭包中被保存起来。待到函数被真正需要求值的时候,之前传入的所有参数都会被一次性用于求值。
假设我们要编写一个计算每月开销的函数。在每天结束之前,我们都要记录今天花掉了多少钱。代码如下:
var monthlyCost = 0;
var cost = function( money ){
monthlyCost += money;
};
cost( 100 ); // 第1 天开销
cost( 200 ); // 第2 天开销
cost( 300 ); // 第3 天开销
//cost( 700 ); // 第30 天开销
alert ( monthlyCost ); // 输出:600
通过这段代码可以看到,每天结束后我们都会记录并计算到今天为止花掉的钱。但我们其实并不太关心每天花掉了多少钱,而只想知道到月底的时候会花掉多少钱。也就是说,实际上只需要在月底计算一次。
如果在每个月的前29天,我们都只是保存好当天的开销,直到第30 天才进行求值计算,这样就达到了我们的要求。虽然下面的cost 函数还不是一个currying函数的完整实现,但有助于我们了解其思想:
var cost = (function(){
var args = [];
return function(){
if ( arguments.length === 0 ){
var money = 0;
for ( var i = 0, l = args.length; i < l; i++ ){
money += args[ i ];
}
return money;
}else{
[].push.apply( args, arguments );
}
}
})();
现在实现一个通用的currying。
var currying = function(fn) {
var args = [];
return function() {
if(arguments.length == 0) {
return fn.apply(this, arguments);
} else {
[].push.apply(args, arguments);
return arguments.callee;
}
}
}
var cost = (function(){
var money = 0;
return function(){
for ( var i = 0, l = arguments.length; i < l; i++ ){
money += arguments[ i ];
}
return money;
}
})();
var cost = currying( cost ); // 转化成currying 函数
cost( 100 ); // 未真正求值
cost( 200 ); // 未真正求值
cost( 300 ); // 未真正求值
alert ( cost() ); // 求值并输出:600
这样也可以是一种方法:
function funnyPlus (num) {
let sum = 0;
const dosum = function (tosum) {
if(arguments.length == 0) return sum;
sum += tosum;
return dosum;
}
return dosum(num);
}