我不知道为什么你会把使用map
叫作"闭包"。闭包是完全不同的东西。map
是高阶函数,即定义为一个操作(接受或返回)函数的函数。这种编程风格可以粗略地称作"函数式"。
像map
这样的函数有优点和缺点。正如一位评论者所指出的,它更加紧凑:
function sum(array) {
var sum = 0;
for (var i = 0; i < array.length; i++) sum += array[i];
return sum;
}
对比。
function sum(array) {
return array.reduce(add);
}
其中,add
是 function add(a, b) { return a + b; }
。
更加紧凑意味着更加易读,同时也减少了出错的可能性。使用名为 add
的函数还可以增强可读性;我们可以很容易地直观地理解这个操作是将数组元素相加。
基本上,所有数组函数都有对应的 for 循环等价形式,但需要设置更多的变量并编写更多的逻辑。例如,map
是
function map(array, fn) {
var result = [];
for (var i = 0; i < array.length; i++) result.push(fn(array[i]));
return result;
}
这段代码可以更加简洁地写成array.map(fn)
。
在许多情况下,我们可能已经定义了所需的元素映射或元素过滤函数。在这种情况下,我们可以直接使用这些函数与map
、reduce
等方法一起使用。
map
及其相关方法的优点在于它们对于稀疏数组也很友好,例如:
var a = [];
a[1000000] = 1;
现在我们将每个元素都加倍:
function double(array) {
var result = [];
for (var i = 0; i < array.length; i++) result.push(array[i] * 2);
return result;
}
这个循环执行一百万次,并返回一个由NaN填充的数组。相比之下,
array.map(elt => elt*2)
这个操作仅对位于位置1000000的单个元素进行操作,并返回稀疏数组,如人们所希望的。
函数式风格还为灵活性开辟了额外的可能性。假设我们想要推广乘法的概念。我可以编写一个高阶函数来创建一个函数,该函数将某个值乘以特定的因子:
function multiply(n) {
return function(x) {
return n * x;
};
}
现在我可以写代码了。
array.map(multiply(2))
这种简明和表达能力的要求在for循环中难以实现。使用
forEach
和
map
等方式可能会比for循环慢,如果您的代码在一个紧密的循环中运行一百万次,这可能是一个问题。但在实际应用中,这很少是一个问题。更好的做法是优先考虑代码的可读性和紧凑性。
然而,并没有人强迫你使用
map
或
filter
。在ES7或任何其它版本中,您可以使用数组推导式来更加可读地完成相同的任务:
[ for (i of array) if (i % 2) i + 1 ]
它结合了filter和map,用于it技术相关内容。
如果你计划编写一个循环遍历数组并从每个元素中产生一些计算的生成器,那么你需要使用for循环,因为没有办法在forEach回调中产生yield:
function *double(array) {
for (var i = 0; i < array.length; i++) yield array[i]*2;
}
function *double(array) {
array.forEach(elt => yield elt*2);
}
map
和reduce
对数组有特定的操作,它们不仅仅像for
循环一样迭代。 - adeneo.map()
的匿名回调函数形成的闭包与代码的运行方式基本无关。当然,函数本身是有关系的,但是调用时形成的闭包并不相关。 - Pointy