【问题标题】:JavaScript: Which is the better approach here... forEach or reduce?JavaScript:这里哪种方法更好…… forEach 还是 reduce?
【发布时间】:2016-02-15 07:40:15
【问题描述】:

对于一个接受数字数组并在包含至少一个偶数时返回 true(否则为 false)的函数,我有以下 2 个解决方案。

解决方案 1(通过 forEach):

var hasEven = function (collection) {
    var isEven = false;
    collection.forEach(function (entry) {
        if (entry % 2 === 0) {
            isEven = true;
            return;
        }
    });
    return isEven;
}

解决方案 2(通过 reduce):

var hasEven = function (collection) {
    return collection.reduce(function (result, entry) {
        return (entry % 2 === 0) ? true : result; 
    }, false);
}

第一个解决方案允许我在找到偶数后立即返回 true。另一方面,第二种解决方案提供了最短的代码。哪个更好?

ps - 是的,有更好的解决方案...比如使用 array.some(...)。但我对比较这里提供的解决方案特别感兴趣。是的,现在解决方案正在正常工作。 :)

【问题讨论】:

  • 我认为您没有测试过该代码。
  • 感谢您指出这一点。如您所知...我是这个游戏的新手,正在学习中。
  • 在要求人们查看问题之前进行测试并通常在问题上投入一些思考与新手无关。
  • 感谢您的评论 Denys,但也没有人天生就具备完整的测试知识。仅供参考,我确实测试了我的“解决方案”..我只是没有正确地做到这一点。希望我会继续向像你这样的人学习并改进......所以是的,我是一个使用 javascript 开发的新手,这显然也会影响我的测试水平。
  • 我终于弄明白了,测试一下,找时间更新一下上面的问题。

标签: javascript arrays


【解决方案1】:

在您编辑的问题中,您说过:

我对比较这里提供的解决方案特别感兴趣

用凿子或螺丝刀敲钉子更好吗?唯一正确的答案是:不要,用锤子。

比较两种使用错误工具完成工作的解决方案最终是一个见仁见智的问题。你喜欢简单吗?使用forEach。简洁?使用reduce。我会在代码审查中将其中任何一个标记为次优选择,并且不会认为两者都比另一个次优。


我原来的答案:

在这种情况下,两者都不是。 Array#some (MDN | spec) 是确定数组是否至少有一个符合条件的条目的合适选择:

var hasEven = function(collection) {
    return collection.some(function(entry) {
        return entry % 2 === 0;
    });
};

Array#some 在回调返回真值后立即停止循环。 some 的返回值是 true 如果回调返回一个真实值,或者 false 如果它没有(所有元素都经过测试并且没有匹配)。

或者使用 ES2015:

// ES2015 (aka ES6) only
let hasEven = function(collection) {
    return collection.some(entry => entry % 2 === 0);
};

或者我们可以变得非常简洁(可能以牺牲可读性为代价,但当我们都真正习惯了箭头函数时可能不会):

// ES2015 (aka ES6) only
let hasEven = collection => collection.some(entry => entry % 2 === 0);

(本节引用the code in your original question。)

我应该注意,您的示例实现都不起作用,forEachreduce 都不起作用。 forEach 总是返回false,因为回调中的return true 只是从回调中返回,根本没有任何作用。 reduce 将 A) 无法测试数组中的第一个条目; B)只告诉你数组中的 last 条目是否是偶数,而不是前面的任何一个是偶数; C) 如果在只有一个条目的数组上调用,则返回第一个条目的 ,而不是 truefalse

正确的forEach 看起来像这样(但会不必要地循环):

var hasEven = function(collection) {
    var result = false;
    collection.forEach(function(entry) {
        result = result || entry % 2 === 0;
    });
    return result;
};

正确的reduce 版本如下所示(但会不必要地循环):

var hasEven = function(collection) {
    return collection.reduce(function(result, current) {
        return result || current % 2 === 0;
    }, false);
};

请注意,在上面,我使用了

return entry % 2 === 0;

而不是

 return (entry % 2 === 0) ? true : false;

=== 的结果已经是一个布尔值。

【讨论】:

  • 感谢您的精彩回答。我正在更新我的问题,谢谢。
  • @Grateful:不需要更新问题。事实上,一旦问题已经有了答案,就对问题进行实质性的改变是不可行的。
  • 根据第一受访者@DenysSéguret 的说法,我实际上已经在这样做了。对此感到抱歉。
  • @Grateful:他只是指出这些功能不起作用。无需更新(同样,一旦回答,实质性地更改问题是不合适的)。我已经回滚了修改 forEach 示例的编辑(这确实使它工作,但有一个毫无意义的 return)。
  • @Grateful:两个原因:首先,我为累加器提供了一个初始值,它修复了我的列表中的项目 (A) 和 (C)。然后它修复(B)的原因是,一旦累加器为真,它将在迭代的其余部分保持为真,因为我正在做return result || entry % 2 === 0; 没有result || 部分,每次迭代都会重置累加器的值,这意味着您最终只会得到最后一个条目的标志。
猜你喜欢
  • 2016-07-11
  • 2010-11-16
  • 1970-01-01
  • 1970-01-01
  • 2014-11-21
  • 1970-01-01
  • 1970-01-01
  • 2013-07-12
  • 1970-01-01
相关资源
最近更新 更多