1

can you please clear up my misunderstanding below?

If the execution context of functions in JS is created when a function is invoked/called and not when it is declared, then in the below code, is inner a closure? If so, why? inner has not yet been invoked and since execution context is created upon invocation there is no way that inner can store a reference to i.

function foo(i) {
   function inner() {
       return i;
   }
   return inner;
}
var f = foo(3);

When does inner have a reference to foo's execution context? When it is invoked or when it is defined? In the above code I have not yet invoked inner.

Also, I appreciate if you explain what JS does when it sees a function definition (in contrast to a function invocation/call)

Thanks,

user3624743
  • 31
  • 1
  • 5

4 Answers4

1

See the comments on how it works.

function foo(i) {
   function inner() { // closure or a new scope is created
       return i;  // but parent scope's variable can be used in child scope
   }
   return inner; // returning reference to function
}
var f = foo(3); // f contains the function reference
f(); // 3, since i is in the parent scope, it is retained.

Since i is a formal parameter, it can be accessed throughout the function since it is at the top most scope, without any closure issues.

Scopes in javascript are function centric. So whenever a function is executed it creates a closure or a scope.

Amit Joki
  • 58,320
  • 7
  • 77
  • 95
  • so, you saying execution context is created when a JS sees a function definition (rather than on function invocation)? – user3624743 May 11 '14 at 17:29
  • I'm editing. Wait @user3624743 – Amit Joki May 11 '14 at 17:31
  • thanks, but i understand that. my question is "WHEN" does [[scope]] for inner holds a reference to foo's execution context? is it when inner is defined or when it is called? – user3624743 May 11 '14 at 17:33
  • I doubt that, please refer here http://davidshariff.com/blog/what-is-the-execution-context-in-javascript/ – user3624743 May 11 '14 at 17:40
  • @AmitJoki - a new closure is created every time `foo()` is executed in the OP's example. Closures are created during execution, not during definition. Obviously, the definition creates the opportunity for a closure, but a closure is actually created when `foo()` is executed and a new one is created each time it is executed. `foo(3)` creates one closure and `foo(4)` creates yet another. – jfriend00 May 11 '14 at 17:41
  • @jfriend00, yes. I thought I thought `i` was available even before foo was called. Thanks for teaching me this – Amit Joki May 11 '14 at 17:43
1

It occurs to me that there may be a terminology issue at play here in conflicting answers. There is a design concept called a closure which one might say is the design of the code that allows there to be a closure. That would obviously occur in the declaration of the code. This is a design concept, but since no code has yet executed, there is no actual object that contains values of variables, references to functions, etc...

There is also the actual function object that persists beyond the time its parent function is executed which makes a closure actual work. That "closure object" is created at execution time and, in fact, a new object is created each time the function is executed.

An actual closure object in your case is created at the time foo() is executed. And, in fact, each time you execute it (and save the return value into a variable), a new closure is created. The code declaration creates the opportunity for a closure, but an actual closure itself is not created until you execute the function foo.

Here's what happens in this code:

function foo(i) {
   function inner() {
       return i;
   }
   return inner;
}

var f = foo(3);
var result = f();

First you declare the foo() function. It is declared to return a reference to the inner() function. This sets up the opportunity for a closure, but no closure is yet created.

Then, when you execute f = foo(3), the function foo is executed. This creates a function scope object (in the interpreter). The argument i in this function scope object has the value of 3 in this particular execution of foo and thus in this scope object. As foo executes, it returns a reference to inner which is then assigned to the variable f. So, the variable f contains a reference to inner().

Normally, when a function finishes executing, it's function scope object is garbage collected (e.g. freed), but in this case inner still has references to that scope object and f contains a reference to that invocation of inner. So, that scope object is not eligible for garbage collection and stays alive. This is called a closure. Because something that lives on has a reference to something inside the function scope, it can't be garbage collected like it would normally be.

The act of defining the functions creates the opportunity for a closure, but the actual closure is created at execution time each time foo() is run.

In fact, if you executed f = foo(3), you create one closure and if you execute g = foo(4), you create yet another closure. Each time you execute foo and save the return value in a variable, a closure is created. Keep in mind that this type of closure is really just a function scope object that can't be immediately garbage collected because some code has retained references to objects in that function scope beyond the lifetime of the function itself.

For me personally, closures were easier to understand when I really just thought about them from the garbage collector point of view. They are simply function scope objects (which all functions have) that can't yet be garbage collected because some code retains a reference to something inside of them. And, the most common way of creating this type of closure is when outside code is given references to local functions inside the parent function.

jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • So these simple function scope objects, their scope chains *aren't* connected to the scope chain of the calling function because then you'd get dynamic scope instead of lexical scope? – Ian Warburton Sep 09 '15 at 12:48
  • @IanWarburton - I'm not quite sure what you're asking. Javascript uses a stack for function calls and return values, but unlike a language like C/C++, a function scope is not on the stack because it can have a different lifetime from the execution of the function itself and thus it is just an object that is garbage collected. Variable references in parent scopes in Javascript are lexical (based on how the code is declared) only, not based on call stack. So, a function has access to variables that are declared in a parent scope, regardless of call stack or calling order. – jfriend00 Sep 09 '15 at 21:58
0

When JS creates a function, it sets its scope property equal to the current environment: http://ecma-international.org/ecma-262/5.1/#sec-13.2

When JS executes a function, it creates a new environment and sets its "outer" (=parent) pointer to the Scope of the function: http://ecma-international.org/ecma-262/5.1/#sec-10.4.3

So the answer to your question is: the closure is created when the function is defined, not when invoked. To clarify, function object is created each time the program reaches the "function" line. If you call your outer function twice, there will be two distinct function objects (with two distinct [[scopes]]).

gog
  • 10,367
  • 2
  • 24
  • 38
  • Thanks, so when js reaches the definition of inner, it creates a function object and sets it scope to the execution context of foo - and hence closure is created? But am not sure what you meant by "outer" pointer, please explain. – user3624743 May 11 '14 at 17:51
  • @user3624743: basically, it's a pointer to a higher stack frame: http://ecma-international.org/ecma-262/5.1/#sec-10.2 – gog May 11 '14 at 17:54
  • @georg: "stack frame" implies "call stack", that's not what it is. It's a pointer to the parent frame in the *scope* "tree". – Bergi May 11 '14 at 17:58
  • thanks I appreciate. The ECMAScript spec looks too technical, you know of any annotated reference? – user3624743 May 11 '14 at 17:58
  • How can you say a closure is created when the function is defined? That simply isn't correct. `foo(3)` and `foo(4)` each create separate closures when they are EXECUTED. The third paragraph in your answer is just not right - you were going well up until the third paragraph. The definition creates the opportunity for a closure, but that actual closure is created when the outer function is executed. Only then is there a live scope that can be captured into a closure. – jfriend00 May 11 '14 at 18:03
  • @jfriend00 can you please explain your answer as a new entry? – user3624743 May 11 '14 at 18:10
  • @jfriend00: good point, I clarified in the post. – gog May 11 '14 at 18:43
0

Closure is a pair of a) function's code and b) chain of call frames. Call frame is essentially structure holding local variables and arguments.

So when you return that inner function you returns something like this:

struct Function {
  var functionBody;     // compiled function body
  var outerScopeChain = { i:3,
                          nextScope: null };
};

Each function-object in JS is a closure in fact, outerScopeChain is null for global functions.

c-smile
  • 26,734
  • 7
  • 59
  • 86