1

I'm a bit stumped by the exact order of execution of a particular for loop I'm playing with, in Codepen. Check out these two loops, which both do the same thing:

var a = ['orange','apple']; 
for (var i=0; i<2;i++) {
    alert(a[i]);
}

for (var j=0, fruit; fruit = a[j++];) {
    alert(fruit);
}

You can see this in action here: http://codepen.io/nickbarry/pen/MYNzLP/

The first loop is the standard, vanilla way of writing a for loop. As expected, it alerts "orange", then "apple".

I wrote the second loop using a suggestion from MDN (search for "idiom", here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/A_re-introduction_to_JavaScript ).

It works, but I don't quite understand why. My understanding of for loops, which is obviously incorrect in some way (more than one way?) is that: * The for loop evaluates the truthiness of the second expression before it runs the first time. So it seems that when the for loop is evaluating the truthiness of the second expression, it should increment j before setting the value of fruit. So the first time through the loop, fruit should equal "apple". * And the loop should only run once, because after the first time through, when it's evaluating the second expression again to see if it's still true, it should once again increment j before it returns a value to fruit, and since there is no value at index position 2, it should return a falsy result, and exit the loop.

I don't understand what actually IS happening. Does the for loop run once before the second expression is evaluated? But that seems impossible, because if that happened, the alert would alert nothing the first time through, since fruit wouldn't yet have a value.

Also, the author of the MDN article seemed to like the second way of writing the loop - is there a reason that way is better? It uses fewer characters, which is good, I guess. Does skipping the third expression in the for loop save significant time? Or is it just a "it's cool because it's clever" sort of thing?

Nicholas Barry
  • 558
  • 2
  • 5
  • 15
  • 1
    The reason it works is that it is a post-increment, not a pre-increment. Your assumptions would be true if it was `++j` instead of `j++`. – Jesse Kernaghan Apr 16 '15 at 02:59
  • 1
    The second way of writing the loop is excellent if your objective is to make enemies. There's no real benefit, it's harder to read, it will halt prematurely if there's a falsey value in the array and it's probably slower (though testing is needed to be certain). – Lye Fish Apr 16 '15 at 03:02
  • 1
    Note that MDN is a wiki. Any half-wit can add content. That same article actually suggests `for-in` for arrays without giving a full explanation of all the issues that may be encountered. – Lye Fish Apr 16 '15 at 03:05
  • i would like to point out that a for loop is valid as long as it has the the following structure `for(; ; ){}`. JS doesn't care what goes between those semi colons but they must exist. Your loop doesn't work because you are trying with index -1 which is invalid. the loop fails on the 1st iteration itself and doesn't continue further. – Ashesh Apr 16 '15 at 03:10
  • 1
    If you *really* want to know how a `for` is supposed to be evaluated, have a look at the spec: http://www.ecma-international.org/ecma-262/5.1/#sec-12.6.3 . – Felix Kling Apr 16 '15 at 03:24
  • @LyeFish: the article says "Note that if someone added new properties to Array.prototype, they will also be iterated over by this loop", which covers it i think. that said, they could have mentioned the main benefit of using for-in on arrays: vastly better sparse array iteration: think about what arr[9999]=0; does to arr.length on an other-wise empty array. sparse arrays are rare, but it's good to know about, and is worth mentioning. – dandavis Apr 16 '15 at 03:46
  • @dandavis: It doesn't cover the non-guarantee of order, the performance degradation or the unexpected stuff you'll encounter on DOM collections (not technically Arrays, but people don't understand that). You're right about sparse Arrays, but if you have an Array *that* sparse, you're likely using the wrong structure to begin with. At that point, there's little reason to use an Array. – Lye Fish Apr 16 '15 at 16:38
  • Thanks, @JesseKernaghan - that is exactly the answer I needed. – Nicholas Barry Apr 16 '15 at 17:37
  • And thanks, @LyeFish. Good to know it's just being clever for the sake of being clever - I won't use that syntax in for loops again. – Nicholas Barry Apr 16 '15 at 17:37

3 Answers3

5
for (var j=0, fruit; fruit = a[j++];) {
    alert(fruit);
}

In pseudocode is equal to:

initialize j = 0 and fruit = undefined

assign fruit = a[j] (j = 0, fruit = 'orange')
j = j + 1 (j = 1)
check fruit for being truthy (true)

alert(fruit) ('orange')

assign fruit = a[j] (j = 1, fruit = 'apple')
j = j + 1 (j = 2)
check fruit for being truthy (true)

alert(fruit) ('apple')

assign fruit = a[j] (j = 2, fruit = undefined)
j = j + 1 (j = 3)
check fruit for being truthy (false)

exit loop

Important note:

The postfix unary ++ operator works as:

  1. We return the current value of the variable
  2. We increment the value of the variable

Does skipping the third expression in the for loop save significant time?

It does not save anything at all

Also, the author of the MDN article seemed to like the second way of writing the loop - is there a reason that way is better?

It's not better in any way. Author just thinks it's cool and author likes to be cool (while they are not).

zerkms
  • 249,484
  • 69
  • 436
  • 539
0

A for loop is really just a shorthand way of writing a while loop. e.g. this loop

for(var i = 0, j = 10; i < 10; i++, j++) {
  alert(i + ", " + j);
}

is just a shorter way of writing

var i = 0, j = 10;
while(i < 10) {
  alert(i + ", " + j);
  i++; j++;
}

So that mans this loop

for(var j=0, fruit; fruit = a[j++];) {
    alert(fruit);
}

is the same as this

var j = 0, fruit;
while(fruit = a[j++]) {
  alert(fruit);
}
Tesseract
  • 8,049
  • 2
  • 20
  • 37
0

You can follow through the order of execution of JavaScript's for loop using SlowmoJS: http://toolness.github.io/slowmo-js/

The homepage already has the for loop loaded into the console for demonstration purposes, but you evaluate the order of operation of any code, as you see fit.

shmuli
  • 5,086
  • 4
  • 32
  • 64