我们可以将匿名函数(anonymous function)作为参数,这种操作具有普遍意义。

map实现

1
2
3
4
5
function map(arr,fn){
var ret = [];
for (let item of arr) ret.push(fn(item));
return ret;
}

上面的操作对数组中的每个元素进行某种变换。

另一种常见的事情是对数组中的每个元素进行累加。例如:

1
2
3
4
5
6
7
8
9
10
11
function sum(arr){
var ret = 0;
for(let i = 0;i < arr.length;i++) ret += arr[i];
return ret;
}

function join(arr) {
var ret = '';
for(let i = 0;i < arr.length;i++) ret += arr[i];
return ret;
}

sum和join函数很像,我们可以将它们抽象一下,把具有共性的代码写成一个通用的函数,将数组的元素合并成一个单一的值。

1
2
3
4
5
function reduce(fn,arr,init){
var s = init;
for (let i = 0;i < arr.length;i++) s = fn(s,arr[i]);
return s;
}

从而上面的sum和join函数可以变成下面的写法:

1
2
const sum = arr => reduce((a,b) => a + b,arr,0);
const join = arr => reduce((a,b) => a + b,arr,'');

让我们回过头来看map函数,当你需要对数组中的每一个元素依次进行处理时,实际情况可能是到底按照哪一种次序进行遍历实际上是无关紧要的:无论从头到尾,还是从尾到头都可以得到相同的结果。如果我们有2个CPU可以用,我们可以写一些代码,使得每个CPU遍历一般的元素,于是一瞬间map函数的运行效率就快了一倍。同理,我们可以将计算任务分配到多台服务器上。

如果我们将map和reduce函数看做任何人都可以调用并且确实是每个人都能用的函数,只需要找到一个超级天才,让他写出能够在全世界庞大的服务器阵列上分布式运行map和reduce函数,所有以前在单机上能够进行的循环操作(loop)的代码依然能够使用,并且速度提高了几十亿倍,同样的代码可以在很短的时间内处理完巨型问题!