ECMA-/Javascripts Array.prototype.forEach

发布于 2024-09-28 01:24:40 字数 1443 浏览 6 评论 0原文

Javascript (ECMAscript) 从 1.6 版(ECMAscript 第 3 版,2005 年)开始支持 Array.prototype.forEach 方法。因此,相当多的浏览器已经支持该方法,并且与 jQuery 的 $.each() 方法相比,它的速度快得令人难以置信。
(实际上,无论哪个 Javascript 库,它都击败了所有实现)

与 jQuery 相比,它的速度大约快 60-70%。亲自尝试一下 JSPerf 上的 forEach 与 jQuery

到目前为止,我使用它的唯一缺点是,我无法找到一种方法来尽早打破迭代。与 for 一样,whiledo-while 有一个 break 语句,jQuery 的 .each()< /code> 支持return false 来打破循环。

我研究了ECMAScript Edition 5 规范(我发现的最新版本),但他们没有提到从该循环中提前中断。

那么,问题来了,Douglas Crockford 先生会将此称为设计错误吗?
我是否错过了一些东西并且可以尽早打破这样的循环?

编辑

感谢您迄今为止的回答。我想由于没有人提出“本机”解决方案,因此确实没有实现该解决方案(也许是一个功能?)。不管怎样,我不太喜欢建议的方法,所以我闲逛了一下,终于找到了一个我喜欢的方法(至少更好)。看起来像:

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。效果很好。

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

Javascript (ECMAscript) supports the Array.prototype.forEach method since version 1.6 (ECMAscript edition 3, 2005). So quite a lot of browser already support that method and it's incredibly fast in comparison to jQuery's $.each() method for instance.
(Actually it beats all implementations, regardless which Javascript library)

In comparison to jQuery it's about 60-70% faster. Try it yourself on forEach vs. jQuery on JSPerf.

The only downside I have so far using it is, I can't figure a way to break the iteration early. Like for, while and do-while have a break statement, jQuerys .each() supports the return false to break the loop.

I looked into the ECMAScript Edition 5 Specifications (the latest I found), but they don't mention an early break from that loop.

So, question, would Mr. Douglas Crockford call this a design error?
Am I missing something and it is possible to break such a loop early?

Edit

Thanks for the answers so far. I guess since nobody came up with a "native" solution, there really is no implementation for that (maybe a feature?). Anyway, I don't really like the suggested methods so I fooled around a little and finally found one I do like (at least, better). Looks like:

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;
    }
});

This is "real" production code. I looked for a nice way to lookup the css3 transform properties and I got lost in ecma5 specs & weird Javascript forums :-)

So, you may pass the array object itself as third parameter into the .forEach callback. I create a copy from the original array, calling slice(0) and set its .length property to 0 as soon as I found what I'm looking for. Works quite well.

If someone comes up with a better solution I'll edit this of course.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

梓梦 2024-10-05 01:24:40

好吧,您可以使用 every 来代替。如果提供的回调函数为数组中的每个元素返回 true(真值),则该函数将返回 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 ,其行为方式完全相反;当回调函数返回 true 值时,立即返回 true;如果从未返回 true 值,则立即返回 false。在这种情况下,return true 将是您的“break”语句。向后是的,但它使您不必简单地返回 true 来让循环继续。

现在,如果您关心性能,我建议仅使用普通的 for 循环,因为调用函数时会产生显着的开销,因为这会在较大的数组中快速累加。使用本机函数会有所帮助,但重复调用用户定义函数的开销仍然存在,而且并非微不足道。至少这是我的经验,你当然应该做自己的测试。

Well, you could use every instead. The function is designed to return true if the provided callback function returns true (truthy) for every element in the array, and false otherwise. Key point here is that once the callback function returns a falsly value, every immediatly returns false without iterating over the rest of the array. So just ignore the return value, and treat every as if it were forEach.

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

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

   return true;
});

In this example, alert will only fire 3 times.

Of course the big cavet here is that you must return a truthy value if you want the loop to continue. In fact if you return nothing (undefined) the loop will stop. Alternativly, you could use some which behaves in the exact opposite manner; immediatly returns true when the callback function returns a truthy value and false if it never does. In this case, return true would be your "break" statement. Backwards yes, but it saves you from having to return true simply to have the loop continue.

Now, if you are concerened with performance, I'd recomend just using a normal for loop, as there is significant overhead incurred when calling functionas that will add up very quickly with larger arrays. Using native functions helps somewhat, but the overhead of repeated calls to user-defined functions still exists and is non-trivial. At least this has been my experience, you should of course do your own testing.

残花月 2024-10-05 01:24:40

您可以抛出一个错误来中断迭代:

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;
    }
}

这不太漂亮。我同意——规格错误。

You could throw an error to break out of the iteration:

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;
    }
}

This isn't exactly pretty. I agree -- spec bug.

这个俗人 2024-10-05 01:24:40

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

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

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

I would assume that you have a chunk of code that needs to be run against every single element. Don't use forEach to find an element or likewise "stop in the middle" operations. Apply this function to every element in an array.

You could (I think) use some sort of global indicator to check and return false if "found" or something.

var found = false;
array.forEach(function (k, v) { 
    if (found) 
    { 
        return false; 
    } 
    else 
    { 
        if (v == 1) 
        { 
            found = true; 
        }
    } 
}); 
怀中猫帐中妖 2024-10-05 01:24:40

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

打破 forEach-ing 的一个选项当然是抛出某些东西,尽管这并不是人们真正想要使用 throw 的方式...

I think I'd use some other construct if I want to loop to search.

An option to break out of the forEach-ing is of course to throw something, though it's not really the way one would want to use throw...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文