Are local variables faster?
For years, I’ve heard that local variables in JavaScript are faster than global variables when used inside of functions. Logically, this always made sense to me: the longer the scope chain the longer it would take to look up the chain and find a particular variable. If the variable was local, however, the search would be very short. I accepted this to be true and preached it like everyone else. However, now I’m not so sure.
I wrote up a very quick experiment to see if this were the case. I tested on Safari 3 (Windows), Opera 9.02, Internet Explorer 7, and Firefox 2.0.0.6. The results are interesting and I’m still trying to understand them:
- In Safari 3 (Windows), using local variables typically takes longer than using globals. However, there is a decent amount of time when the two are exactly equal.
- In Opera 9.02, using globals routinely show up as slower than locals. There are, though, some instances when the two are equal and, every so often, an instance when globals are faster than locals (though this is clearly the least likely to occur).
- In Internet Explorer 7, the two end up equal most of the time. The second most common occurrence is globals being faster than locals. I have seen instances where locals are faster than globals, but it doesn’t happen very often.
- In Firefox 2.0.0.6, global variables are much faster than locals by a factor of at least 3. This was the most surprising to me. Never did the two come close in timing.
So what does all of this mean? Should we start doing browser detects to determine whether to use global or local variables? Of course not, that would be insane. What it does mean is that perhaps the way we’ve thought about JavaScript scope chains isn’t entirely accurate.
I’m wondering if the creation and destruction of local variables contributes to the timing discrepancies in this experiment. Please take a look at the source code and let me know if you see anything that may be skewing these results. Please feel free to play with the experiment and a little bit and let me know what results you come up with.
Disclaimer: Any viewpoints and opinions expressed in this article are those of Nicholas C. Zakas and do not, in any way, reflect those of my employer, my colleagues, Wrox Publishing, O'Reilly Publishing, or anyone else. I speak only for myself, not for them.
Both comments and pings are currently closed.




10 Comments
In your experiment you use the following code:
var color = "blue";
function returnColorFromGlobal(){
return color;
}
function returnColorFromLocal(){
var color = "blue";
return color;
}
In the global case you initialize the variable once. In the local case it needs initialized once per function call.
In the case of Safari, the KJS developers have done some great optimisations to variable lookup recently. http://bugs.webkit.org/show_bug.cgi?id=14868 is the bug tracking merging those changes over to WebKit. It’s almost done, the patch just needs some final polish. I’ve heard some impressive numbers mentioned about this optimisation, but I’ll let it speak for itself once it makes it way into Safari.
Mark Rowe on August 26th, 2007 at 9:56 pm
I did such an experiment quite a while back and it does show that local variables are faster than global variables[1].
The only difference in the experiment being, using a local function pointer to invoke a function instead of calling the function directly.
http://gopalarathnam.com/examples/javascript/scope.html
[1] Except in IE7, surprisingly I read about this optimization (!) at MSDN. I’m still trying to find out why this is the case.
Gopal Venkatesan on August 27th, 2007 at 12:49 am
Even more interesting in my opinion is what effect closures have on the runtime of functions. For example in a closure the used variables must be looked up in both the real function and the one where this function is in. In qooxdoo (http://qooxdoo.org) we found out that closures often slow down function execution time when these functions also access the outer variables. I think that, when local functions are slower, it also makes sense that local-local variables like the locals from the outer functions are slower again. I have not done any separated test like you, but it sounds like an interesting thing. Especially because closures are nowadays often used to handle private data/functions in JS.
Sebastian Werner on August 27th, 2007 at 2:05 am
I found out that global variables are not much faster than local in Firefox. In the test case you don’t take into account the state of the context in which JavaScript is executed and get screwed results.
Change the test so that local variable is timed first to see what I am talking about.
JCurtis on August 27th, 2007 at 5:31 am
@Mike – Cool, I can’t wait to see how it performs. Your point about variable initialization is well-taken though I think this is a very common use case. I’ve often told people to create a local copy of a global variable to increase performance but this test seems to indicate that the advice was invalid.
@Gopal – I just ran your test a few times and it tends to show the same results as mine: the local tests are taking longer than the global ones. Did you find a specific case in which this was not the norm?
@Sebastian – You’re right, closures definitely slow down overall performance due to scope chain lookup of variables. That’s why I purposely kept this test without closures so as not to affect the results.
@JCurtis – How did you come to this come to this conclusion? My test (and Gopal’s) shows a dramatic time difference in favor of global variables. I did change the test around and ended up with the same results. Do you have a different test that proves your assertion?
Nicholas C. Zakas on August 27th, 2007 at 2:27 pm
See my example:
http://scidezy.de/speedtest.html
I think so it is more correct. You spend a lot of time on variable initialization. Thats why http://www.jslint.com/ gives a warning when you make variable initialization inside of block (for example "for").
Dmitry Monin on August 27th, 2007 at 4:39 pm
@Dmitry – Ah, very good! I believe your test is a better benchmark than mine. I’ll need to revisit this some more. Thanks!
Nicholas C. Zakas on August 27th, 2007 at 6:04 pm
I rearranged yours. But I can’t confirm my words on second test. Now it might be interesting to understand why this happens.
JCurtis on September 10th, 2007 at 8:48 am
I too noticed JCurtis’ results. In fact, if you open the link to the experiment in a background tab (middle-click or ctrl+left-click) the timings will be close to the same every time.
Or just use the following code. I moved the document.write statements after the loops, it seems to affect it somehow.
var color = "blue";
function returnColorFromGlobal(){return color;}
function returnColorFromLocal(){var color = "blue";return color;}
var result, i=0;
var start = null, stop = null;
start = new Date();
for (i=0; i < 100000; i++){result = returnColorFromGlobal();}
stop = new Date();
start = new Date();
for (i=0; i < 100000; i++){result = returnColorFromLocal();}
stop = new Date();
document.write("Using global: ");
document.write(stop – start);
document.write("ms<br>");
document.write("Using local: ");
document.write(stop – start);
document.write("ms<br>");
BP on November 7th, 2007 at 2:05 pm
ah! Please ignore the code in my last post.
(Note that the start and stop variables were mistakenly reused)
No, I’m not a horribly bad coder, just in a hurry.
*This* code confirms the aforementioned results.
var color = "blue";
function returnColorFromGlobal(){return color;}
function returnColorFromLocal(){var color = "blue";return color;}
var result, i=0;
var gstart = null, gstop = null;
gstart = new Date();
for (i=0; i < 100000; i++){result = returnColorFromGlobal();}
gstop = new Date();
var lstart = null, lstop = null;
lstart = new Date();
for (i=0; i < 100000; i++){result = returnColorFromLocal();}
lstop = new Date();
document.write("Using global: ");
document.write(gstop – gstart);
document.write("ms<br>");
document.write("Using local: ");
document.write(lstop – lstart);
document.write("ms<br>");
BP on November 7th, 2007 at 2:09 pm
Comments are automatically closed after 14 days.