地图和最大在洛达什的奇怪行为

Weird behaviour of map and max in lodash

本文关键字:地图      更新时间:2023-09-26
var a = [ [1,2,3], [4,5,6], [7,8,9] ];
_.map( a, _.max );
// gives [3, -Infinity, -Infinity]

我已经在我的 Chrome 浏览器、lodash 网站上对其进行了测试。

上面的代码不应该返回 [3, 6, 9] 吗?

我可以使用forEach获得正确的结果:

var a = [ [1,2,3], [4,5,6], [7,8,9] ];
var result = [];
_.forEach( a, function(arr) { result.push(_.max(arr)); } );

总体结论

我在 GitHub 上打开了一个问题:https://github.com/lodash/lodash/issues/379多亏了jdalton,这个问题现在已经解决了。示例:→ jsFiddle

细节(为什么结果"奇怪"?

我从未与Lodash详细合作过,但这是我的研究:

检索集合的最大值。如果集合为空或为假-Infinity则返回.
— 洛达什文档: _.max()

每个组的测试_.max()都完美地工作:

_.max([1,2,3]);  // 3
_.max([4,5,6]);  // 6
_.max([7,8,9]);  // 9

现在,我尝试在 _.map() 的回调函数中手动调用_.max()

var a = [ [1,2,3], [4,5,6], [7,8,9] ];
alert(_.map( a, function(val) {
    return _.max(val);
}));

工作正常!那么,这与作为第二个参数提供_.max()之间的区别在哪里? _.map()实际上向回调函数发送了 3 个参数:

(value, index|key, collection).
— Lodash 文档: _.map()

现在考虑_.max()的第二个参数:

2.[回调=标识] (函数|对象|字符串):每次迭代调用的函数。如果提供了属性名称或对象,它将是 分别用于创建 ".pluck" 或 ".where" 样式回调.
— 洛达什文档: _.max()

结论:_.max()也传递了_.map()提供的第二个和第三个参数。第二个参数在这里很重要!为它传递真实值(例如整数 != 0)可以让函数返回-Infinity

测试用例(→ jsFiddle):

alert(_.max([1,2,3], 0)); // 3
alert(_.max([1,2,3], 1)); // -Infinity
alert(_.max([1,2,3], 2)); // -Infinity

这来自源代码中执行的布尔检查:https://github.com/lodash/lodash/blob/f0f7eee963966516490eb11232c9e9b4c6d0cc6c/dist/lodash.js#L3431

因为callback(第二个参数)是一个真值,我们将直接跳转到 else 分支。在那里,callback被重新分配如下(三元运算也将采用 else 分支):

lodash.createCallback(callback, thisArg, 3);

createCallback()定义在这里。它为我们的特定输入参数返回以下函数(这些参数1, null, 3,有关详细信息,请参阅_.max()):

return function(object) {
  return object[func];
};

假设,我们将其保存在一个名为callback(→ jsFiddle)的变量中:

var callback = _.createCallback(1, null, 3);

使用 object = 1(或 2、3 或 6 等)调用该函数会导致undefined(这很明显)。

回到_.max(),我们看到有一个循环将当前值(来自回调函数)与初始/最后一个值进行比较,并且按照函数开头的设置-Infinity

undefined > -Infinity永远不会产生 true,因此-Infinity将保持"最大值"。