Javascript的reduce()函数有哪些优点?(以及map()函数)

6

我正在考虑是否在需要编写的函数中使用Javascript中的reduce()方法,该函数类似于以下内容。

var x = [some array], y = {};
for (...) {
    someOperation(x[i]);
    y[x[i]] = "some other value";
}

现在,这可以显然地被写成以下形式的reduce()函数:

x.reduce(function(prev, current, index, arr) {
    someOperation(current);
    prev[current] = "some other value";
    return prev;
}, {})

或者类似的东西。这两种方法之间是否存在性能或其他差异?或者在Web编程环境中,是否有其他原因(例如浏览器支持),使其中一种方法更受青睐?谢谢。

4个回答

4
  1. mapfilterreduceforEach等(更多信息请参见:https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array#Iteration_methods)比普通循环更好,因为:
    • 它们更加优雅;
    • 它们鼓励函数式编程(请参阅函数式编程的益处);
    • 你需要编写函数并将迭代变量作为参数传递进去。这是因为JavaScript没有块级作用域。像mapreduce这样的函数可以让你的工作更轻松,因为它们会自动设置迭代变量并将其传递给你的函数。
  2. 虽然IE9声称支持它们,但它们已经在官方的javascript/ecmascript规范中了。如果你关心使用IE8的用户,那就是你的权利。如果你真的关心,你可以覆盖Array.prototype,只针对IE8及更早版本进行“修复”。

4
尽管我更喜欢使用这些操作(reduce、map、filter等),但由于一些浏览器不支持它们的实现,使用它们仍然不可行。当然,您可以通过扩展Array原型来“修补”它,但那也是开启潘多拉魔盒。
我认为这些函数本质上并没有什么问题,而且我认为它们可以让代码更好,但目前最好不要使用它们。一旦更高比例的人口使用支持这些函数的浏览器,我认为它们将是公平竞争的。
就性能而言,由于函数调用的开销,这些函数可能比手写的for循环慢。

请问您为什么认为reduce()可以让代码更好?即使它的性能较慢,您为什么还是喜欢它?我理解在并行计算中map/reduce操作的价值,但是在单机上(即使是多核心),这些优势是否也同样存在呢?谢谢。 - Jay
2
@Jayraj Jog:我喜欢它们,因为它们抽象出了非常常见的过程,所以代码变得更加清晰,没有设置循环的样板文件。正如您所知,JavaScript通常在单线程环境中运行,因此在并行环境中获得的map/reduce的好处并不适用。因此,对于Web开发的目的,这些map和reduce函数基本上是为了帮助提高可读性和可写性而存在的。显然,这只是我的观点,但我希望我为您提供了一些见解。 - Cristian Sanchez
对于性能评价加1。根据jsperf上的测试,在Firefox和Chrome中,普通循环大约快10倍,在iPhone上快5倍。 - RobG
如果浏览器支持是一个问题,那么你可以使用Underscore.js,它提供了相同的函数,但如果本地实现可用,则使用本地实现。 - Andrejs

2

reduce 用于从数组中返回一个值,该值是对先前元素的结果进行顺序处理得出的。

reduceRight 也是一样,但是从末尾开始反向处理。

map 用于返回一个数组,其中所有成员都经过了函数处理。

两种方法都不会影响数组本身。

var A1= ['1', '2', '3', '4', '5', '6', '7',' 8'];

// 这个 map 的使用返回原始元素转换为数字的新数组-

A1=A1.map(Number); // >> A1 的每个元素都被转换为数字

// 这个 reduce 对数组元素求和-

var A1sum= A1.reduce(function(a, b){ return a+b;});

// A1sum>> 返回值: (Number) 36

它们在旧浏览器中不受支持,因此您需要为它们提供替代品。如果您所做的一切都可以在简单的循环中复制,那么就不值得。

计算总体标准差是一个例子,其中 map 和 reduce 都可以有效地使用-

Math.mean= function(array){
    return array.reduce(function(a, b){ return a+b; })/array.length;
}
Math.stDeviation=function(array){
    var mean= Math.mean(array);
    dev= array.map(function(itm){return (itm-mean)*(itm-mean); });
    return Math.sqrt(dev.reduce(function(a, b){ return a+b; })/array.length);
}


var A2= [6.2, 5, 4.5, 6, 6, 6.9, 6.4, 7.5];
alert ('mean: '+Math.mean(A2)+'; deviation: '+Math.stDeviation(A2))

0

kennebec - 做得不错,但你的 stDeviation 函数调用了两次 reduce 和一次 map,而实际上只需要一次调用 reduce 就可以了(这样会更快):

Math.stDev = function (a) {
    var n = a.length;
    var v = a.reduce(function (v, x) {
      v[0] += x * x;
      v[1] += x;
      return v;
    }, [0,0]);
    return Math.sqrt( (v[0] - v[1]*v[1] / n) / n );
}

应该在分配给v [1]时进行数字转换,以确保字符串数字不会影响结果。最后一行中的除数在大多数情况下应该是(n-1),但这取决于OP。 :-)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接