最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

jquery - ECMA-Javascripts Array.prototype.forEach - Stack Overflow

programmeradmin2浏览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 parison to jQuery's $.each() method for instance.
(Actually it beats all implementations, regardless which Javascript library)

In parison 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 es up with a better solution I'll edit this of course.

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 parison to jQuery's $.each() method for instance.
(Actually it beats all implementations, regardless which Javascript library)

In parison 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 es up with a better solution I'll edit this of course.

Share Improve this question edited Oct 20, 2010 at 2:45 Yi Jiang 50.2k16 gold badges139 silver badges136 bronze badges asked Oct 19, 2010 at 19:51 jAndyjAndy 236k57 gold badges313 silver badges363 bronze badges 4
  • 1 Time for a goto break anyone? – Josh K Commented Oct 19, 2010 at 19:54
  • 4 Well, if you could break early, it wouldn't really be forEach. It'd be forSome. ;o) – user113716 Commented Oct 19, 2010 at 20:07
  • @patrick: funny, anyway I like the jQuery implementation for the feature that you can break an .each() loop early. – jAndy Commented Oct 19, 2010 at 20:09
  • Yeah, that would seem handy. I wonder how the performance would pare on a large set where you simulate early termination by wrapping the code in an if(). – user113716 Commented Oct 19, 2010 at 20:14
Add a ment  | 

4 Answers 4

Reset to default 7

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 reend 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.

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.

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

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...

发布评论

评论列表(0)

  1. 暂无评论