繁体   English   中英

ECMA- / Javascripts Array.prototype.forEach

[英]ECMA- / Javascripts Array.prototype.forEach

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

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

到目前为止我唯一使用它的缺点是,我无法想象早点打破迭代的方法。 就像forwhiledo-while有一个break语句一样,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规范和奇怪的Javascript论坛:-)

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

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

嗯,你可以使用every来代替。 如果提供的回调函数为数组中的每个元素返回true (truthy),则该函数被设计为返回true否则返回false 这里的关键点是,一旦回调函数返回一个错误的值, every immediatly返回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将是您的“break”语句。 向后是的,但它可以让你不必return true只是为了让循环继续。

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

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

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

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

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

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。

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

打破forEach-ing的一个选择当然是throw一些东西,虽然它并不是人们想要使用抛出的方式......

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM