[[Scope]] that is initialized with information about the scope in which the function was created. The
[[Scope]] property is actually a list of variable objects accessible from the function’s containing scope. When you create a global function, it’s
[[Scope]] property has only the global object in the list; when a function is created inside of a global function, the global function’s activation object is at the front of
[[Scope]] and the global object is second.
When a function is executed, an activation object is created and then has a scope chain associated with it. The scope chain is used for identifier resolution and is created in two steps:
- The objects in the function object’s
[[Scope]]property are copied into the scope chain in the same order.
- A new activation object is created with variables for the executing function. This object contains the definitions for
arguments, and local variables (including named arguments), and is pushed onto the front of the scope chain.
Given this description of identifier resolution, it makes sense that local variables should have faster identifier resolution than variables from other scopes because the search for a matching name is much shorter. But how much faster? In order to answer this question, I set up a series of tests using variables of different scope-depth.
My first tests involved writing a simple value to variables (literally, the value 1). The results were interesting.
Those results were for variable writes, and I wondered if the performance for variable reads would be any different. Variable reads turned out to be somewhat faster than writes even though the same trends emerged.
Once again, Internet Explorer and Firefox are the slowest, with Opera showing respectable performance. And once again, Chrome and the latest WebKit nightly show flat performance based on identifier depth. Also notable is the same strange jump in Firefox 3.1 Beta 2′s variable access times once you’re no longer dealing with local variables.
One interesting thing I found in my research is that Chrome has a performance penalty for accessing global variables. The access time for global variables remains constant regardless of identifier depth but that value is 50% higher than the amount of time it takes to access local variables with the same identifier depth.
What does all of this mean? It basically means that my research supports that advice that you should use local variables whenever possible. In almost all browsers, local variables are faster for both reading and writing than out-of-scope variables including globals. You can take advantage of this knowledge in several ways:
- Watch the variables being used in a function. If you notice a function using an out-of-scope variable more than once, store it in a local variable and use that instead. You’ll be reducing the number of out-of-scope identifier resolutions for that variable to one. This is especially important for global variables, which are always the last object in the scope chain.
- Avoid using the
withstatement. It temporarily augments the execution context’s scope chain by adding a new variable object to the front. This means that local variables actually move to an identifier depth of two during execution of the
with, imposing a performance penalty.
- Avoid using
try-catchif you know an error will always occur. The catch clause augments the scope chain in the same manner as the
withstatement. There is no penalty for running code in the
tryportion of the code, so it is still advisable to use
try-catchfor dealing with unexpected errors.
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.