3 ms·
The "even nicer [array for loop] idiom" is pretty cool: for (var key = 0, value; value = someArray[key++];) { // value is already defined by for loop
by henryw 13y ago
The "even nicer [array for loop] idiom" is pretty cool:
for (var key = 0, value; value = someArray[key++];) {
// value is already defined by for loop
console.log('index: ' + key, 'value: ' + value);
}
Also, I finally understand closures:
"Whenever JavaScript executes a function, a 'scope' object is created to hold the local variables created within that function. It is initialised with any variables passed in as function parameters. This is similar to the global object that all global variables and functions live in, but with a couple of important differences: firstly, a brand new scope object is created every time a function starts executing, and secondly, unlike the global object (which in browsers is accessible as window) these scope objects cannot be directly accessed from your JavaScript code... A closure is the combination of a function and the scope object in which it was created."
- Drakim 13y agoUnless I'm mistaken, wouldn't this loop terminate prematurely if the array contains any falsy value, such as undefined, null, false, NaN, or 0?
- joebadmo 13y agoYes, there's a note right after: Note that this trick should only be used for arrays which you know do not contain "falsy" values (arrays of objects or DOM nodes for example). If you are iterating over numeric data that might include a 0 or string data that might include the empty string you should use the i, len idiom instead.
- Wintamute 13y agoYou're correct. Seems like a pretty useless/dangerous idiom to me. How often can you be sure that in 100% of cases your loop will never iterate a 0, an empty string or some other falsey value?
- al2o3cr 13y agoThe above code will print out an off-by-one index for each element (starts at 1 and not 0). Given that the loop also fails to complete if someArray contains a falsy value, I'd say this trick falls into the "too cute to be safe" category.
- Stratoscope 13y agoThat was a great way to iterate over a non-sparse array such as an array of objects... Back in 2006 when this article was written. In fact, this was an even better way to write that loop in 2006: for( var value, i = -1; value = array[++i]; ) { console.log( 'index: ' + i, 'value: ' + value ); } Basically the same thing except for the pre-increment instead of postincrement. In some of the browsers of that day (at least IE), preincrement was faster. And this version gives you the correct array index inside the loop, unlike the off-by-one in the other version. I was so proud of myself when I discovered this alternative that I wrote a recipe for the jQuery Cookbook recommending it as the fastest way to iterate over a typical array of objects such as you might receive from a JSON request. It also used to be a great idea to optimize your machine code programs by looking up the CPU cycles for each instruction. Fewer cycles = faster code. Of course, that doesn't work any more, what with pipelining and out-of-order execution. Alas, these nifty JavaScript loops are not the fastest any more either. Fewer operations != faster code. The optimization guy for V8 explained this to me at Google I/O 2012. He said that V8 can optimize the heck out of references into an array where all the types are the same (either primitive values, or objects that all have the same properties). But if you ever try to reference outside the bounds of the array, it throws the whole thing back into deoptimized code. And that is the problem. These nifty loops rely on reading the nonexistent element just past the end of the array. That's their termination condition. It turns out that with modern optimizing compilers, the plain old traditional JavaScript loop is faster across the board: for( var i = 0, n = array.length; i < n; ++i ) { var value = array[i]; console.log( 'index: ' + i, 'value: ' + value ); } (There is still a minor benefit to using preincrement instead of the more traditional postincrement in some modern browsers.) I put together a JSPerf for this a while ago: http://jsperf.com/mikes-loops/2 http://jsperf.com/mikes-loops/2 I was quite embarrassed to learn how poorly my clever loop works in modern browsers!
- pixl97 13y ago>I was quite embarrassed to learn how poorly my clever loop works in modern browsers! What's really embarrassing is IE js performance. Since I keep an ancient copy of of Netscape 9.0.0.6 on my computer I decided to try it so see how much browsers have improved. It doesn't seem to upload results I'll post them here in the same order as the testing page. 17.25 16.72 5.94 8.81 18.90 23.28 20.92 23.58 This is on the same computer that was pulling 5000+ on the fastest tests. Browsers have come a long way.
- jarek-foksa 13y agoAs of ES6 I would limit myself to only three styles of writing array for-loops: 1. Crockford's C style with cached array length (fast and flexible, but verbose): for (let index = 0, length = array.length; index < length; index += 1) { console.log(index, array[index]); } 2. Functional style (terse and flexible, but slow): array.forEach((value, index) => console.log(index, value)); 3. Python style (fast and terse, but not flexible): for (let value of array) { console.log(value); } By "flexible" I mean being able to e.g. iterate over items with odd indexes or in reverse direction.
- lost_my_pwd 13y agoSmall problem with the conditional using the array assigment. If a value in the array is not "truthy", the loop will stop at that element -- e.g. ['a', 0, 'b', 'c'] will only print out the first element in your example.