0

I am following along with an article on javascript closures.

In trying to learn the particulars of execution context, I came across a result that surprised me.

var globalVar = 'g';
var inner;
var outer = function() {
  var outerVar = 'o';
  inner = function() {
    var innerVar = 'i';
    console.log(innerVar, outerVar, globalVar);
  }
}

outer()
inner() // Q: What does this log out?

http://jsfiddle.net/6zvsh/

This actually outputs i o g.

I expected to see i undefined g.

Here is my understanding of the process. I would like to understand my error:

  1. inner is declared as a property on the global object and the value is set to undefined
  2. outer is invoked.
  3. An execution context is created for outer whose scope chain includes outerVar and the global object.
  4. The value of the inner property on the global object is assigned a reference to the function definition.
  5. The execution context for outer finishes. (the related scopes are removed? marked for GC?)
  6. inner is invoked.
  7. An execution context is created whose scope chain includes innerVar and the global object.
  8. outerVar is not found in scope

Can someone please explain why outerVar is defined?

SimplGy
  • 20,079
  • 15
  • 107
  • 144
  • 1
    You just have discovered closures! [How do JavaScript closures work?](http://stackoverflow.com/questions/111102/how-do-javascript-closures-work) – Bergi Apr 26 '14 at 19:48
  • This could be the answer, too: http://stackoverflow.com/a/11148475/111243 – SimplGy Apr 26 '14 at 19:49
  • That comment might be a bit more pandering than necessary, @Bergi. I think this is a question about some nuance between invocation and declaration that I don't understand, rather than needing a general overview. I'm reading a few different overviews, just the same :) – SimplGy Apr 26 '14 at 19:59

1 Answers1

1

When a function is created, it references its surrounding execution context as the scope, creating a closure for it.

Let's step through it:

1. inner is declared as a property on the global object and the value is set to undefined

1.5. the outer function is created, referencing the global scope as its parent scope

2. outer is invoked.

3. An execution context is created for outer whose scope chain includes outerVar and the global object.

…because the chain link of the new execution context references the parent scope of outer, which is (assigned in 1.5) the global scope. outerVar is a variable in this new execution context.

4. The value of the inner property on the global object is assigned a reference to the function definition.

…and the function's parent scope is set to the execution context of outer.

5. The execution context for outer finishes. (the related scopes are removed? marked for GC?)

…but is not garbage-collected because it is still referenced as the parent scope of the inner function which is still living (not garbage).

6. inner is invoked.

7. An execution context is created whose scope chain includes innerVar and the global object.

The new execution context has a scope chain link to inners parent context, which is the execution context created above for the outer call (which has the chain link to the global scope). innerVar is a variable in this new execution context.

8. outerVar is not found in scope

…chain.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • 1
    Awesome. I think the key thing I missed is the timing of assigning the scope to the function object. I summed it up like this: Q: Why does it have access to `outerVar`? A: Because when `outer` is run, a function object is created for `inner` whose [[scope]] is assigned the value of outer's execution context. The outer's execution context's scope is a chain which contains the Activation/Variable object (arguments, outerVar) and the global object. Because the GC can see a reference from the global `inner` property to the executionContext scope of outer, that scope is maintained. – SimplGy Apr 26 '14 at 20:25
  • Yes, exactly. Only I didn't focus on using the correct terminology (didn't have the time to cite the [relevant spec section](http://es5.github.io/#x10.3)), please excuse if I have mixed the terms "scope" and "execution context". – Bergi Apr 26 '14 at 20:30