Can someone provide an explanation of variable scope in JS as it applies to objects, functions and closures?
3 Answers
Global variables
Every variable in Javascript is a named attribute of an object. For example:-
var x = 1;
x is added to the global object. The global object is provided by the script context and may already have a set of attributes. For example in a browser the global object is window. An equivalent to the above line in a browser would be:-
window.x = 1;
Local variables
Now what if we change this to:-
function fn()
{
var x = 1;
}
When fn
is called a new object is created called the execution context also referred to as the scope (I use these terms interchangeably). x
is added as an attribute to this scope object. Hence each call to fn
will get its own instance of a scope object and therefore its own instance of the x attribute attached to that scope object.
Closure
Now lets take this further:-
function fnSequence()
{
var x = 1;
return function() { return x++; }
}
var fn1 = fnSequence();
var fn2 = fnSequence();
WScript.Echo(fn1())
WScript.Echo(fn2())
WScript.Echo(fn1())
WScript.Echo(fn2())
WScript.Echo(fn1())
WScript.Echo(fn1())
WScript.Echo(fn2())
WScript.Echo(fn2())
Note: Replace WScript.Echo
with whatever writes to stdout in your context.
The sequence you should get is :-
1 1 2 2 3 4 3 4
So what has happened here? We have fnSequence
which initialises a variable x
to 1 and returns an anonymous function which will return the value of x
and then increment it.
When this function is first executed a scope object is created and an attribute x
is added to that scope object with the value of 1. Also created in the same execution object is an anonymous function. Each function object will have a scope attribute which points to the execution context in which it is created. This creates what is know as a scope chain which we will come to later. A reference to this function is returned by fnSequence
and stored in fn1
.
Note that fn1
is now pointing at the anonymous function and that the anonymous function has a scope attribute pointing at a scope object that still has an x
attribute attached. This is known as closure
where the contents of an execution context is still reachable after the function it was created for has completed execution.
Now this same sequence happens when assigning to fn2
. fn2
will be pointing at a different anonymous function that was created in a different execution context that was create when fnSequence
was called this second time.
Scope Chain
What happens when the function held by fn1
is executed the first time? A new execution context is created for the execution of the anonymous function. A return value is to be found from the identifier x
. The function's scope object is inspected for an x
attribute but none is found. This is where the scope chain comes in. Having failed to find x
in the current execution context JavaScript takes the object held by the function's scope attribute and looks for x
there. It finds it since the functions scope was created inside an execution of fnSequence
, retrieves its value and increments it. Hence 1 is output and the x
in this scope is incremented to 2.
Now when fn2
is executed it is ultimately attached to a different execution context whose x
attribute is still 1. Hence executing fn2
also results in 1.
As you can see fn1
and fn2
each generate their own independent sequence of numbers.

- 24,650
- 8
- 50
- 93

- 187,081
- 35
- 232
- 306
-
This answer is really imprecise. `var x = 1;` and `window.x = 1;` are not equivalent. In the second case `x` is deleteable. In the first, it is not. Using the term "attribute" instead of "variable" or "property" is unhelpful, since "attribute" already has two meanings for JavaScript developers, neither of which is the one you're using. Also, your description of execution contexts is wrong: if you're going to use terms from the ECMAScript spec then you really need to use them accurately. [continued] – Tim Down Jul 08 '10 at 14:56
-
When `fn` is called, `x` is created as a property of the *variable object*, which is bound to the execution context but is not the same thing as it. Using the term "scope" interchangeably with "execution context" is also unhelpful: again, they are closely related and every execution context does have a scope chain, but they are not the same thing. For example, a scope chain may be altered by code within an execution context by using a `with` statement or a `catch` clause. – Tim Down Jul 08 '10 at 15:00
-
Sorry to be critical: what you say is broadly correct, but you've explained it using terms from the ECMAScript spec inaccurately. – Tim Down Jul 08 '10 at 15:04
-
1@Tim: I accept all of your criticisim. However I find that super-fine precision whilst able to clarify even the most nuanced of behaviours is only properly absorbable by the clever bods. The rest of us mere mortals look on in bewilderment. I've been burned many times for being ever so slightly "imprecise" but these days I no longer worry about it. A simple "mental model" that works 99% of the time and is easy to grasp is better than a complex "accurate and precise model" that is difficult to understand. This is why most engineers still use Newtonian physics over Quantum physics. – AnthonyWJones Jul 08 '10 at 15:14
-
Fair enough. I think I'd suggest using other terms for that though, rather than ones from the spec. Having written all that, I felt guilty and found an answer of yours that I liked and upvoted it :) – Tim Down Jul 08 '10 at 15:49
Variables not declared with var are global in scope. Functions introduce a scope, but note that if blocks and other blocks do not introduce a scope.
I could also see much information about this by Googling Javascript scope. That's really what I would recommend. http://www.digital-web.com/articles/scope_in_javascript/

- 793
- 7
- 13
Functions introduce a scope. You can declare functions inside other functions, thereby creating a nested scope. The inner scope can access the outer scope, but the outer can not access the inner scope.
Variables are bound to a scope, using the var keyword. All variables are implicitly bound to the top-level scope. So if you omit the var keyword, you are implicitly referring to a variable bound to the top level. In a browser, the top level is the window object. Note that window is it self a variable, so window == window.window

- 115,121
- 27
- 131
- 155