54

Reading through the jQuery source I stumbled upon the following piece of code (available here):

for (; i < length;) {
    if (callback.apply(object[i++], args) === false) {
        break;
    }
}

Why is a for loop used here instead of a while loop?

3
  • 6
    I wonder if this code is shorter when minimized? It's horrible code, and the jQuery guys are smart people, so I'd think it's for minification purposes. Commented Aug 24, 2011 at 0:20
  • 9
    Removing all whitespace, @aroth's version is shorter. Any variable name that can be shortened is used an equal number of times. Could get even shorter. while(i<length&&callback.apply(object[i++],args)!==false); Commented Aug 24, 2011 at 0:33
  • It could be argued that replacing all while loops with this form of for in the minified code compresses better. No idea if that's what they had in mind, though. Commented Aug 24, 2011 at 8:50

7 Answers 7

44

I vote for someone having an affinity for bad coding style. That's the only explanation I can see for both the for loop and the i++ being placed inside of an array subscript. I think this would be better:

while (i < length && callback.apply(object[i], args)) {
    i++;
}

Or if you happen to feel that the === operator in the original example has value, then:

while (i < length && callback.apply(object[i], args) !== false) {
    i++;
}

Another possible reason for doing this may have been as a performance optimization. Although this quick benchmark that I put together seems to disprove that theory. On Windows the while loop above is 20% faster than the original for loop in Chrome, in IE and Firefox both loops perform the same. On OS X the for loop has a 10% advantage in Firefox, there is no difference between the two in Chrome, and Safari prefers the while loop by 6%.

So from a performance standpoint it's a wash. If anything then judging by market share you would probably want to optimize for Chrome on Windows before optimizing for Firefox on Mac, in which case the while loop would be preferred.

Which says to me that it's unlikely that performance optimization played a factor with this code. And I return to my original theory that it's just an example of poor coding style making it past the code-review process.

Sign up to request clarification or add additional context in comments.

10 Comments

The strict false test is necessary since that's the one return value that will break the iteration.
Wouldn't 'i' be out by 1 in your example?
The second version is required for equivalency to the original in cases where the callback could return undefined or 0. The first version would not work identically in those cases.
Still, the code is not equivalent. If the loop breaks because the callback returns false, i will be one less here than in the original code.
@Jordi - The original code returns after the loop executes without making any additional reference to i, and i is scoped locally to the function. So for all practical purposes they are the same. There's no reason in this case to care about the value of i after the loop terminates.
|
26

Probably because it was "refactored" from a for (x in obj) loop: http://james.padolsey.com/jquery/#v=1.3.2&fn=jQuery.each

Comments

21

Here is the commit that introduced this oddity.

Commit message:

jquery core: code reduction at $.each and $.curCSS.

Snip from the diff:

-        for ( var i = 0, length = object.length; i < length; i++ )
-          if ( callback.apply( object[ i ], args ) === false )
+        for ( ; i < length; )
+          if ( callback.apply( object[ i++ ], args ) === false )

It would appear that the author simply missed the opportunity to change the for into a while.

Comments

6

First, there is never a length cost for using a for loop over a while loop, but you get additional functionality with the for loop, so some coders just always use the for:

for(;<condition>;){}
while(<condition>){}

That said, I think the purpose here may be for consistency with the surrounding code.

For example, here is part of the original code. As you can see, in this code you can stay in the "for" loop mode of thinking the whole time, so it feels more consistent:

if (args) {
    if (isObj) {
        for (name in object) {
            if (callback.apply(object[name], args) === false) {
                break;
            }
        }
    } else {
        for (; i < length;) {
            if (callback.apply(object[i++], args) === false) {
                break;
            }
        }
    }
}

Compare this to replacing the second loop with a while. When you read this code, you have to switch from the "for" loop mode of thinking to the "while" loop mode of thinking. Now I don't know about you, but I find it slightly faster for my eyes to switch between the loop conditions above as opposed to the loop conditions below. This is because in the above case I can just concentrate on the conditions, whereas in the below case my eyes are drawn to reread the while and the for each time because they are different:

if (args) {
    if (isObj) {
        for (name in object) {
            if (callback.apply(object[name], args) === false) {
                break;
            }
        }
    } else {
        while (i < length) {
            if (callback.apply(object[i++], args) === false) {
                break;
            }
        }
    }
}

Comments

2

I've found that things like this occur when I rewrite things or if multiple people touch a piece of code. Can't see any particular reason for it.

I hope i gets initialized properly above this block.

Comments

0

The shortest and most honest answer is pretty short "just because". There is absolutely no practical reason to do it, we don't gain any profit from such 2-smiles loop.

As for aforementioned reasons, such as:

  • refactoring - which is most possible, but nevertheless this is not an excuse.
  • minification considerations - which is less, less possible.
  • psychological/readability/code supporting issues - I very dubious that somebody write such code keeping in mind that a user can be confused for some code constructions and loose concentration;

well, as for these reasons - all of them definitely worth mentioning, but, to be honest, jquery code style is, well, not ideal. Sometimes there are reasons why it is so, some times, it's just a matter of fact.

Production code is not always the most beautiful code. Reading production-ready, hardcore code on any language is always for good, but is not 100% about code style. Say, vim is beautiful, very powerful software, but (as for me) some purist can be surprised with it source code. Though loops stuff is ok ))))

Comments

0

So t will run at least once, because if you use a while loop if the logic is false it wont run. For lopp even if it is false it will run atleast once.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.