ECMA- / Javascripts Array.prototype.forEach

时间:2010-10-19 19:51:58

标签: javascript jquery ecma262

Javascript(ECMAscript)支持自1.6版本以来的Array.prototype.forEach方法(ECMAscript edition 3,2005)。因此,相当多的浏览器已经支持该方法,并且与jQuery的$.each()方法相比,它的速度非常快。
(实际上它胜过所有实现,无论哪个Javascript库)

与jQuery相比,它的速度提高了约60-70%。在JSPerf上的forEach vs. jQuery上自己尝试一下。

到目前为止我唯一使用它的缺点是,我无法想办法尽早打破迭代。与forwhiledo-whilebreak语句一样,jQuerys .each()支持return false来打破循环。

我查看了 ECMAScript第5版规范(我发现的最新版本),但他们没有提到该循环的早期中断。

那么,问题一下,Douglas Crockford先生会称之为design error吗? 我错过了什么,有可能提前打破这样的循环吗?

修改

感谢目前为止的答案。我想既然没有人想出一个“原生”解决方案,那真的没有实现(可能是一个功能?)。无论如何,我真的不喜欢建议的方法,所以我愚弄了一点,最后找到了一个我喜欢的(至少,更好)。看起来像:

var div     = document.createElement('div'),
divStyle    = div.style,
support     = jQuery.support,
arr         = ['MozTransform', 'WebkitTransform', 'OTransform'];

arr.slice(0).forEach(function(v,i,a){    
    if(divStyle[v] === ''){
       support.transform = v;
       a.length = 0;
    }
});

这是“真正的”生产代码。我找了一个查找css3转换属性的好方法,我迷失了ecma5 specs&奇怪的Javascript论坛: - )

因此,您可以将数组对象本身作为第三个参数传递给.forEach回调。我从原始数组创建一个副本,调用slice(0)并在找到我正在寻找的内容时将其.length属性设置为0。效果很好。

如果有人提出了更好的解决方案,我当然会对此进行编辑。

4 个答案:

答案 0 :(得分:7)

好吧,您可以使用every代替。如果提供的回调函数为数组中的每个元素返回true(truthy),则该函数被设计为返回true,否则返回false。这里的关键点是,一旦回调函数返回一个错误值,every立即返回false而不迭代数组的其余部分。因此,只需忽略返回值,并将every视为forEach

[1, 2, 3, 4, 5].every(function(e) {
   alert(e);

   if (e > 2) return false; //break

   return true;
});

在此示例中,alert只会触发3次。

当然,最重要的一点是,如果你想让循环继续,必须返回一个真值。事实上,如果你什么都不返回(未定义),循环将停止。或者,您可以使用some,其行为完全相反;当回调函数返回一个truthy值时,immediatly返回true,如果它从未返回,则返回false。在这种情况下,return true将是您的“休息”声明。向后是的,但它可以让你免于return true只是让循环继续。

现在,如果你对性能有所了解,我建议只使用一个普通的for循环,因为调用functionas时会产生很大的开销,而这些函数会在较大的数组中很快加起来。使用本机函数有所帮助,但重复调用用户定义函数的开销仍然存在且非常重要。至少这是我的经验,你当然应该做自己的测试。

答案 1 :(得分:1)

我认为你需要针对每个元素运行一大堆代码。不要使用forEach来查找元素或同样“停在中间”操作。将此函数应用于数组中的每个元素。

你可以(我认为)使用某种全局指标来检查并返回false,如果“找到”或其他什么。

var found = false;
array.forEach(function (k, v) { 
    if (found) 
    { 
        return false; 
    } 
    else 
    { 
        if (v == 1) 
        { 
            found = true; 
        }
    } 
}); 

答案 2 :(得分:1)

你可以抛出一个错误来突破迭代:

if (typeof BreakIteration == "undefined") {
  BreakIteration = new Error("BreakIteration");
}

try {
    [0,1,2,3,4].forEach(function(key, value) {            
        console.log(key + ': ' + value);

        if (value == 3) {
            throw BreakIteration;
        }
    });
} catch (error) {
    if (error !== BreakIteration) {
        throw error;
    }
}

这不是很漂亮。我同意 - spec bug。

答案 3 :(得分:0)

如果我想循环搜索,我想我会使用其他一些构造。

打破forEach-ing的选项当然是throw的东西,虽然它不是真正想要使用throw的方式......