JavaScript Map Reduce:奇怪的行为

时间:2013-04-03 22:01:57

标签: javascript mapreduce

var t = [-12, 57, 22, 12, -120, -3];

t.map(Math.abs).reduce(function(current, previousResult) {
    return Math.min(current, previousResult);
}); // returns 3

t.map(Math.abs).reduce(Math.min); // returns NaN

我不明白为什么第二种形式不起作用。欢迎任何解释。

编辑:技术背景:Chrome和Firefox JavaScript引擎。请参阅ES5 reduce http://www.ecma-international.org/ecma-262/5.1/#sec-15.4.4.21

2 个答案:

答案 0 :(得分:6)

Math.min接受多个参数。这与parseInt或其他类似函数不起作用的原因完全相同。你需要自己绑定参数。

indexarray等值添加到Math.min

如果我们按照以下步骤操作,我们可以确认:

首先,我们代理Math.min:

var oldMath = Math.min;
Math.min = function (){
   console.log(arguments)
   return oldMath.apply(Math, arguments);
}

然后我们运行第二个版本:

[-12, 57, 22, 12, -120, -3].reduce(Math.min);

哪些日志:

[-12, 57, 1, Array[6]]

由于Array [6]不是数字,因此结果为NaN


以下是来自MDN的非常相似的示例:

["1", "2", "3"].map(parseInt);

虽然人们可以期待[1,2,3]  实际结果是[1,NaN,NaN]

parseInt通常与一个参数一起使用,但需要两个参数。第二个是基数  对于回调函数,Array.prototype.map传递3个参数:元素,索引,数组  第三个参数被parseInt忽略,但不是第二个参数,因此可能会产生混淆。

答案 1 :(得分:3)

reduce的回调被称为传递四个参数:previousValuecurrentValueindexarray。由于Math.minvariadic函数,因此您的代码为:

t.map(Math.abs).reduce(Math.min); // returns NaN

相当于:

t.map(Math.abs).reduce(function(current, previousResult, index, array) {
  return Math.min(current, previousResult, index, array);
});

结果为NaN的原因是:最后一个参数array不是数字。

你也可以像high-ordered function这样解决这类问题:

function binary (fn) {
  return function (a, b) {
     return fn.call(this, a, b);
  }
}

然后:

t.map(Math.abs).reduce(binary(Math.min));

会有效。