views:

335

answers:

7

In AS3 I believe you should initialise all variables outside loops for increased performance. Is this the case with JavaScript as well? Which is better / faster / best-practice?

var value = 0;

for (var i; i < 100; i++)
{
    value = somearray[i];
}

or

for (var i; i < 100; i++)
{
    var value = somearray[i];
}
+12  A: 

In theory it shouldn't make any difference in JavaScript, since the language does not have block scope, but only function scope.

I'm not sure about the performance argument, but Douglas Crockford still recommends that the var statements should be the first statements in the function body. Quoting from Code Conventions for the JavaScript Programming Language:

JavaScript does not have block scope, so defining variables in blocks can confuse programmers who are experienced with other C family languages. Define all variables at the top of the function.

I think he has a point, as you can see in the following example. Declaring the variables at the top of the function should not confuse readers into thinking that the variable i is held in the scope of the for loop block:

function myFunction() {
  var i;    // the scope of the variables is very clear

  for (i = 0; i < 10; i++) {
    // ...
  }
}
Daniel Vassallo
+1 for telling OP truths about JS scope. I'm wondering whether to downvote answers that say otherwise!
spender
@Kieranmaine: I didn't say it doesn't affect performance. I just made an argument for putting them outside the loops, irrelevant of performance.... I don't have any references for the performance arguments, but you didn't cite any in your answer either :)
Daniel Vassallo
@Kieranmaine: do you have a source for that?
Andy E
@Kieranmaine: AFAIK even if you declare variables inside of a loop, `ecma- / javascript` will bump those up at runtime. That is called "Hoisting". So there should not be any difference.
jAndy
I'd +1 again for such a controversial answer. Well done!
spender
@spender: Thanks ... It certainly wasn't my intention to be controversial :)
Daniel Vassallo
@Andy E - Trying to find it now.
Castrohenge
+1 and retracted my comment. Forgot about hoisting, but I do suggest you hoist the var awnser to the top and the 'extra' scope info to the bottom ;o)
BGerrissen
It's not the var declaration inside loops that slows down performance, but static value assignments (ie. len = list.length)
BGerrissen
+1 and retract from me too. my example turned out to be the same as what BGerrissen points out.
Castrohenge
-1 for missing the point. This isn't about the index of the for loop, its about what goes on inside the loop.
mkoistinen
@mkoistinen: I don't think I missed the point. I only cited an authoritative source that still recommends putting variable declarations outside blocks, weather there is a performance gain or not. Mine wasn't intended to be an exhaustive answer (it doesn't answer the performance question, and I emphasized that), but I still think it adds value to the topic of the question... I don't think this answer merits the 6 downvotes it got (2 of them retracted later).
Daniel Vassallo
@Daniel, you're correct. I verbally retrace my down-vote here, but it seems I cannot actually do it until you edit your post again for some reason.
mkoistinen
@mkoistinen: Yes, there's some mechanism to prevent tactical downvoting on SO... Did a minor edit :)
Daniel Vassallo
A: 

Your first case is better practice. The second initializes a new variable each iteration of the loop, rather than simply assigning a new value. Actual performance difference is likely very small, however 2nd example is still a bad practice IMO.

KP
Why the downvote with no explanation? If you disagree with an answer, justify it. It's petty otherwise.
KP
It's the same variable each time around the loop, regardless of where you declare `var` or indeed whether you declare it at all. `for` and `var` don't work like that (which is why we get the Closure Loop Problem).
bobince
@bobince: fair enough; at the same time this isn't the case in many languages, and promotes approaches which may confuse others interpreting it, and cause issues if the OP uses the same approach in other, more strict languages. Still a bad idea IMO. Just because you 'can' do something, doesn't mean you should.
KP
A: 

Well, that depends on what you're trying to achieve... if value suppose to be only a temporary variable inside loop block then it's much clearer to use second form. It's also more logical and verbose.

Crozin
+3  A: 

Next year, all browsers will have JS engines that precompile the code so the performance difference (which comes from parsing the same block of code again and again plus executing the assignment) should become negligible.

Also, never optimize for performance unless you have to. Keeping variables close to the place where you need them the first time keeps your code clean. On the negative side, people who are used to languages with block scopes might be confused.

Aaron Digulla
+7  A: 

The ECMA-/Javascript language hoists any variable which is declared anywhere to the top of a function. That is because this language does have function scope and does not have block scope like many other C-like languages.
That is also known as lexical scope.

If you declare something like

var foo = function(){
    for(var i = 0; i < 10; i++){
    }
};

This gets hoisted to:

var foo = function(){
    var i;
    for(i = 0; i < 10; i++){
    }
}

So it does not make any difference in performance (But correct me if I'm totally wrong here).
A much better argument for not declaring a variable somewhere else than at the top of a function is readability. Declaring a variable within a for-loop might lead to the wrong assumption that this variable can only be accessed within the loop body, which is totally wrong. Infact you can access that variable anywhere within the current scope.

jAndy
+1 informative!
mkoistinen
+20  A: 

There is absolutely no difference in meaning or performance, in JavaScript or ActionScript.

var is a directive for the parser, and not a command executed at run-time. If a particular identifier has been declared var once or more anywhere in a function body(*), then all use of that identifier in the block will be referring to the local variable. It makes no difference whether value is declared to be var inside the loop, outside the loop, or both.

Consequently you should write whichever you find most readable. I disagree with Crockford that putting all the vars at the top of a function is always the best thing. For the case where a variable is used temporarily in a section of code, it's better to declare var in that section, so the section stands alone and can be copy-pasted. Otherwise, copy-paste a few lines of code to a new function during refactoring, without separately picking out and moving the associated var, and you've got yourself an accidental global.

In particular:

for (var i; i<100; i++)
    do something;

for (var i; i<100; i++)
    do something else;

Crockford will recommend you remove the second var (or remove both vars and do var i; above), and jslint will whinge at you for this. But IMO it's more maintainable to keep both vars, keeping all the related code together, instead of having an extra, easily-forgotten bit of code at the top of the function.

Personally I tend to declare as var the first assignment of a variable in an independent section of code, whether or not there's another separate usage of the same variable name in some other part of the same function. For me, having to declare var at all is an undesirable JS wart (it would have been better to have variables default to local); I don't see it as my duty to duplicate the limitations of [an old revision of] ANSI C in JavaScript as well.

(*: other than in nested function bodies)

bobince
I still can't decide if I'm with Crockford or not on this one. Declaring variables inside blocks feels a bit like using conditional function statements (which is naughty)... However, I agree with your points as well :) #confused
Daniel Vassallo
+1 I disagree with Crockford's reasoning (quoted in Daniel's answer), as JavaScript developers we shouldn't be writing code so that other "C family" programmers can understand it. I often use *var* inside *if* blocks and loops because it makes more sense to me.
Andy E
-1 The OP is asking if vars in the body of the loop should be declared before the loop begins. The index value of the loop is clearly a special case (and is hoisted) and doesn't not help the OP at all.
mkoistinen
Loop indexes aren't a special case, they're handled and hoisted in exactly the same way as a normal assignment.
bobince
+1 Crockford is wrong about this one (and others, but I digress). Requiring that `var` is only used at the top of a function is just asking for accidental global variable creation. And having a mass of unrelated variables all declared in one spot is semantically meaningless, especially when some of those variables may end up never being used.
MooGoo
@MooGoo: He'll tell you to use [jsLint](http://www.jslint.com/) to avoid the issues that you mention :)
Daniel Vassallo
Oops, wrong post. Move along.
mkoistinen
Retraced my down-vote, changed to an up-vote for informative.
mkoistinen
+3  A: 

I just did a simple test in Chrome

  var count = 100000000;
    var a = 0;
    console.log(new Date());

    for (var i=0; i<count; i++) {
      a = a + 1
    }

    console.log(new Date());

    var j;
    for (j=0; j<count; j++) {
      a = a + 1;
    }

    console.log(new Date());

    var j;
    for (j=0; j<count; j++) {
        var x;
        x = x + 1;
    }

    console.log(new Date());

Result is that the last test takes ~8 seconds and the previous 2 are only ~2 seconds. Very repeatably and regardless of order.

So, this proves to me, that one should always declare the vars outside of the loop. Curious case to me is the first one where I declare i in the for() statement. This one appears to be just as fast as the 2nd test where I pre-declare the index.

mkoistinen
+1 for proven results.
KP
I tried your test case with 10 million iterations instead of 100 million. Chrome 6.0.472 for Mac (2.93 Ghz Intel Core 2 Duo - 6 GB RAM): http://img691.imageshack.us/img691/3581/chrometest.jpg ... Can't see any difference.
Daniel Vassallo
@KP: results are only proven if you test them yourself or if a large number of people verify them. @mkoistinen: I constructed a fairer test, http://jsfiddle.net/GM8nk/. After running the script a several times in Chrome 5, I could see that there was no consistent winner. All three variations performed better than the others after a few refreshes. -1 from me, I'm afraid. Note, you might want to run [this one](http://jsfiddle.net/GM8nk/1/) in other browsers. IE and Fx didn't like 100 million iterations.
Andy E
I just repeated this a few more times. Results very consistent with my post on Chrome 7.0.503.0 dev on Mac OS 10.6.4.
mkoistinen
So it would seem chrome 7 dev version can not optimize local var declarations within a loop, whereas it can if var declaration taken out of loop ? Anyone know why, as all other answers suggest it should be the same ?
NimChimpsky
@AndyE, your fiddle indeed does look 'fairer'. And, results are about the same for each on my machine as well. I stand corrected.
mkoistinen
@NimChimpsky, I don't know if you can draw that conclusion, actually. I was able to perform the tests as written by Andy E in his jsFiddle above with about the same performance for each. I still cannot explain why the tests I ran locally ''still'' show a performance loss on the test with the declared var inside the loop.
mkoistinen
@mkoistinen: Tried your test in Chrome 7 Dev (using JS Console in Dev Tools), and I get the same exact results. 12-13 seconds for each test case: http://img812.imageshack.us/img812/931/chrome7test.jpg
Daniel Vassallo
@mkoistinen: in all fairness, I just ran my first fiddle on Opera and the results were that the third test *is* slightly slower. But it's only marginal, over 100 million iterations the difference is <20ms so I'm not sure it's worth changing the way you write code to account for the microseconds it will save in the Real World. It is worth me retracting my down vote, though. FWIW, Firefox and IE choke on that many iterations, knocking it down to 1 million shows similar results to Chrome.
Andy E
@mkoistinen, I'm not sure whether to upvote because it was a good idea to run the test; or downvote because you got dodgy/unexplainable results ...
NimChimpsky
@NimChimpsky... I think the jury's still out! =)
mkoistinen
@AndyE. Wow, so based on this simply test, IE sucks 100X more? =)
mkoistinen
+1 its friday afterall, aka poets day,
NimChimpsky
@mkoistinen: IE *and* Firefox ;-) I was impressed by Opera's script engine speed, tbh.
Andy E
Results are all over the place for me, no clear cross-browser winner though there are sometimes significant speed differences. Weird. I think Andy's fiddle is a better test though, putting each candidate in its own function... certainly if the original script is run outside of a function, it shouldn't really be testing anything as the `var` is declaring as global a variable that would be global anyway.
bobince