与Lisp,Haskell不同,JavaScript并非函数式编程语言,但在JS之中可以像操控对象一样操控函数,换句话说,可以在JS中应用函数式编程技术。
什么是函数式编程?
函数式编程通过使用函数来将值转换成抽象单元,接着用于构建软件系统。
举个很普通且低级的例子:假设有一个数组,数组元素都是数字,我们想要计算它的平均值和标准差,如果使用非函数式编程那么就是这个样子:
var data = [1,2,3,4,5];
var total = 0;
for(var i = 0; i < data.length; i++)
total += data[i];
var mean = total / data.length; //平均数为3
total = 0;
for(var i = 0; i < data.length; i++) {
var deviation = data[i] - mean;
total += deviation * deviation;
}
var stddev = Math.sqrt(total / (data.length-1)); //标准差为2
采用函数式编程那么就是这个样子(这里会用到数组方法map()和reduce(),ES3未包含这两种方法,所以下面会先进行判断,如果有map()和reduce()就直接使用,否则就自行定义):
var map = Array.prototype.map?function(a, f) { return a.map(f); }
:function(a, f) {
var results = [];
for(var i = 0,len = a.length; i < len; i++) {
if (i in a) results[i] = f.call(null,a[i],i,a);
}
return results;
};
var reduce = Array.prototype.reduce?function(a,f,initial) {
if(arguments.length > 2)
return a.reduce(f, initial);
else
return a.reduce(f);
}
: function(a,f,initial) {
var i = 0, len = a.length,accmulator;
if(arguments, length > 2)
accmulator = initial;
else{
if(len == 0)
throw TypeError();
while( i < len){
if(i in a){
accumulator = a[i++];
break;
}
else
i++;
}
if(i == len) throw TypeError();
}
while( i < len) {
if ( i in a)
accumulator = f.call(undefined, accumulator,a[i],i,a);
i++;
}
return accumulator;
});
//下面的代码块就是函数式编程
var sum = function(x,y) { return x+y; };
var square = function(x) { return x*x;};
var data = [1,2,3,4,5];
var mean = data.reduce(sum) / data.length;
var deviations = data.map(function(x) { return x-mean;});
var stddev = Math.sqrt(deviations.map(square).reduce(sum) / (data.length - 1));
用严格的函数式编程的方法来解决问题,会将一个问题分成几部分(函数)来解决。如下图:
函数式编程通过“组合”其他函数的方式来构建更大的函数,以实现更抽象的行为如下图:
最终,一种将函数的部件组成一个完整的系统的方法是取一个值,逐渐的将它“改变”——通过一个原始的或组合的函数——成为另外一个值。