29

I wrote this code to teach myself about JavaScript closures:

function1 = function(){
  var variable = "foo"
  var function2 = function(argument){
    console.log(variable + argument);
  }
  return function2
}

function3 = function1();
function3("bar");

This prints "foobar" as expected. But where does the variable live?

Does it become a property of function3, or stored somewhere else in function3? Does JavaScript traverse some kind of closure chain, similarly to how it traverses the prototype chain? Is it stored in memory somewhere else?

I am trying to understand this more deeply.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Wylliam Judd
  • 9,935
  • 2
  • 26
  • 36
  • 1
    Yes, you could compare this with the prototype-chain, kind of, where each node stores the variables and their values for this particular function-call (important: that particular function-call, not just the function), down to the global scope. That's the same mechanism that allows you to access variables from an outer scope, if the're not defined in your current scope. BUT: there is no chance to print/see/access or modify this thing. It's a construct behind the scenes of your Engine. – Thomas May 27 '16 at 20:27
  • 1
    possible duplicate of [How do JavaScript closures work at a low level?](http://stackoverflow.com/q/31735129/1048572) or [How JavaScript closures are garbage collected](http://stackoverflow.com/q/19798803/1048572)? See also [Where is the variable in the closure stored, stack or heap?](http://stackoverflow.com/q/29225834/1048572) and [Javascript closures on heap or stack?](http://stackoverflow.com/q/16959342/1048572). – Bergi May 28 '16 at 12:22

5 Answers5

39

tl;dr:

where does the variable live?

In the environment it was defined in.

Does it become a property of function3, or stored somewhere else in function3?

No.

Does JavaScript traverse some kind of closure chain, similarly to how it traverses the prototype chain?

Yes.

Is it stored in memory somewhere else?

Yes.


tl;dr 2:

Functions keep a reference to the environment they are created in. When a function is called it creates a new environment whose parent is the environment the function kept the reference to.


Longer explanation:

Whenever a function is executed a new lexical environment is created. The environment has two "fields": an environment record where all the variables are being tracked and a outer lexical environment that refers to, as the name suggested, to the "parent lexical environment".

So when we your code example is evaluated, the initial state of the memory (before executing anything) might look like this (simplified):

+-(Global) lexical environment-+     +-Environment Record-+
+-------------+----------------+     +---------+----------+
| Environment |       *--------+---> |function1|undefined |
|   Record    |                |     +---------+----------+
+-------------+----------------+     |function3|undefined |
|    Outer    |                |     +---------+----------+
|   lexical   |    (empty)     |
| environment |                |
+-------------+----------------+

The global environment doesn't have any outer environment because it is at the top. function1 and function3 are two bindings that haven't been initialized yet (the assignment wasn't evaluated yet).

After creating the function (evaluating function1 = function() { ... }), the memory looks like this:

            +------------------------------------------------------------------------+
            |                                                                        |
            v                                                                        |
+-(Global) lexical environment-+    +-Environment Record-+     +-----Function Object-+---+
+-------------+----------------+    +---------+----------+     +---------------+-----+---+
| Environment |       *--------+--->|function1|    *-----+---->|[[Environment]]|     *   |
|   Record    |                |    +---------+----------+     +---------------+---------+
+-------------+----------------+    |function3|undefined |     |     name      |function1|
|    Outer    |                |    +---------+----------+     +---------------+---------+
|   lexical   |    (empty)     |
| environment |                |
+-------------+----------------+

Now function1 has a value, a function object. Function objects have multiple internal (e.g. [[Environment]]) and external (e.g. name) properties. As the name implies, internal properties cannot be accessed from user code. The [[Environment]] property is very important. Notice how it refers back to the lexical environment the function was created in!

The next step is executing function3 = function1(), i.e. calling function2. As I said at the very beginning, whenever a function is executed a new lexical environment is created. Let's look at the memory just after entering the function:

               +------------------------------------------------------------------------+
               |                                                                        |
               v                                                                        |
   +-(Global) lexical environment-+    +-Environment Record-+     +-----Function Object-+---+
   +-------------+----------------+    +---------+----------+     +---------------+-----+---+
   | Environment |       *--------+--->|function1|          +---->|[[Environment]]|     *   |
   |   Record    |                |    +---------+----------+     +---------------+---------+
+> +-------------+----------------+    |function3|undefined |     |     name      |function1|
|  |    Outer    |                |    +---------+----------+     +---------------+---------+
|  |   lexical   |    (empty)     |
|  | environment |                |
|  +-------------+----------------+
|
|
|
|  +-----lexical environment------+    +-Environment Record-+
|  +-------------+----------------+    +---------+----------+
|  | Environment |       *--------+--->|variable |undefined |
|  |   Record    |                |    +---------+----------+
|  +-------------+----------------+    |function2|undefined |
|  |    Outer    |                |    +---------+----------+
|  |   lexical   |        *       |
|  | environment |        |       |
|  +-------------+--------+-------+
|                         |
+-------------------------+

This looks very similar to the structure of the global environment! We have a lexical environment that has an environment record with two unintialized bindings. But the big difference now is that "outer lexical environment" points to the global lexical environment. How is that possible?

When calling function1 and creating a new lexical environment, we set the value of the new environments "outer lexical environment" field to the value of function1's [[Environment]] field. This is were the scope chain is created.

Now, after executing function1, the memory has this structure:

               +------------------------------------------------------------------------+
               |                                                                        |
               v                                                                        |
   +-(Global) lexical environment-+    +-Environment Record-+     +-----Function Object-+---+
   +-------------+----------------+    +---------+----------+     +---------------+-----+---+
   | Environment |       *--------+--->|function1|    *-----+---->|[[Environment]]|     *   |
   |   Record    |                |    +---------+----------+     +---------------+---------+
+> +-------------+----------------+    |function3|   |      |     |     name      |function1|
|  |    Outer    |                |    +---------+---+------+     +---------------+---------+
|  |   lexical   |    (empty)     |                  |
|  | environment |                |                  |
|  +-------------+----------------+                  +-------------------------+
|                                                                              |
|             +----------------------------------------------------------------+--------+
|             v                                                                |        |
|  +-----lexical environment------+    +-Environment Record-+                  v        |
|  +-------------+----------------+    +---------+----------+                           |
|  | Environment |       *--------+--->|variable |  'foo'   |     +-----Function Object-+---+
|  |   Record    |                |    +---------+----------+     +---------------+-----+---+
|  +-------------+----------------+    |function2|    *-----+---->|[[Environment]]|     *   |
|  |    Outer    |                |    +---------+----------+     +---------------+---------+
|  |   lexical   |        *       |                               |     name      |function2|
|  | environment |        |       |                               +---------------+---------+
|  +-------------+--------+-------+
|                         |
+-------------------------+

Similar like function1, function2 has a reference to the environment created by calling function2. In addition, function3 refers to the function we created because we return it from function1.

Last step: calling function3('bar'):

               +------------------------------------------------------------------------+
               |                                                                        |
               v                                                                        |
   +-(Global) lexical environment-+    +-Environment Record-+     +-----Function Object-+---+
   +-------------+----------------+    +---------+----------+     +---------------+-----+---+
   | Environment |       *--------+--->|function1|    *-----+---->|[[Environment]]|     *   |
   |   Record    |                |    +---------+----------+     +---------------+---------+
+> +-------------+----------------+    |function3|   |      |     |     name      |function1|
|  |    Outer    |                |    +---------+---+------+     +---------------+---------+
|  |   lexical   |    (empty)     |                  |
|  | environment |                |                  |
|  +-------------+----------------+                  +-------------------------+
|                                                                              |
|             +----------------------------------------------------------------+--------+
|             v                                                                |        |
|  +-----lexical environment------+    +-Environment Record-+                  v        |
|  +-------------+----------------+    +---------+----------+                           |
|  | Environment |       *--------+--->|variable |  'foo'   |     +-----Function Object-+---+
|  |   Record    |                |    +---------+----------+     +---------------+-----+---+
|+>+-------------+----------------+    |function2|    *-----+---->|[[Environment]]|     *   |
|| |    Outer    |                |    +---------+----------+     +---------------+---------+
|| |   lexical   |        *       |                               |     name      |function2|
|| | environment |        |       |                               +---------------+---------+
|| +-------------+--------+-------+
++------------------------+
 |
 | +-----lexical environment------+    +-Environment Record-+
 | +-------------+----------------+    +---------+----------+
 | | Environment |       *--------+--->|argument |  'bar'   |
 | |   Record    |                |    +---------+----------+
 | +-------------+----------------+
 | |    Outer    |                |
 | |   lexical   |        *       |
 | | environment |        |       |
 | +-------------+--------+-------+
 +------------------------+

Similar here, a new environment is created and its "outer lexical environment" field points to the environment created when function1 was called.

Now, looking up the value of argument is straightforward, because it exists in the environment's own record. But when looking up variable, the following happens: Since it doesn't exist in the environment's own record, it looks at its "outer lexical environment"'s record. It can do that because it has a reference to it.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
  • Clarification: After `function1` is defined but before its executed, are the Environment Record that holds `variable` and `function2` and the Outer lexical environment that refers to Global stored in memory, or not until `function1` is actually called on line 9? If I'm following you correctly, they're not stored until `function1` is called, at which point `function3` is now defined in the global namespace. That makes sense to me. Do I have that right? – Wylliam Judd May 27 '16 at 23:16
  • 1
    The second environment record is only created when `function1` is called. `function3` is only defined *after* `function1` is executed (and returned the value). – Felix Kling May 27 '16 at 23:42
  • 3
    is there any special tool you use to draw these ASCII diagrams? – Random832 May 28 '16 at 01:11
  • Also, how does this interact with dynamic scopes created by the `with` statement? Are they part of a single chain or are there two parallel chains? – Random832 May 28 '16 at 01:13
  • @Random832: I'm using http://monodraw.helftone.com/ (which is amazing). `with` would, basically like a function call, create a new lexical environment that is at the end of the chain (so, a single chain). However, its a different type of environment, which a different kind of environment record (that is backed by the object passed to `with`). [Spec](http://www.ecma-international.org/ecma-262/6.0/index.html#sec-with-statement-runtime-semantics-evaluation) – Felix Kling May 28 '16 at 01:27
  • @Random832: I usually use Emacs artist-mode for quick&dirty diagrams like that. – Tobia Tesan May 28 '16 at 08:08
  • 1
    Nice answer. I wish more answeres addressing scoping or closures would explain the correlation between Lexical Environment and Variable Environment as you have shown here. – Travis J May 30 '16 at 22:22
  • @FelixKling First of all, this is brilliant. Assuming all these Lexical Environments ( Execution Context ) are created within the Call stack. after `function1` execution, its Execution Context will be removed from the Call stack, then the returned function will be called after a few lines of code using the assigned variable ( `function3`). Until calling the returned function will this closure will be saved in the call stack or will it be copied to somewhere else like a heap. once it's called, it can be pushed to call stack right? – Shamseer K Jan 07 '22 at 04:19
  • 1
    @ShamseerK: Thank you :) Regarding where this information is stored: I'm not familiar with actual JavaScript implementations (e.g. browser engines) so I cannot really answer that question. The specification doesn't really talk about this. It describes the concept of a "execution context stack", and adding to and removing from it, but that's it. I think it does say that this information needs to be retained somehow. This is probably all left to the language that is used to implement the engine. So if it's C or a similar low level language then what you are saying seems to make sense. – Felix Kling Jan 07 '22 at 11:25
  • hi @Felix Kling a lexical environment (function) only has "direct" access to the outer lexical environment and the other lexical environments to which it has access in turn are already thanks to the scope chain (i.e. because the outer lexical environment of that function has access in turn to the lexical environment of its outer and so on), right? –  Jan 28 '23 at 03:16
  • 1
    @Daniel: Yes, that's right. – Felix Kling Jan 28 '23 at 20:06
4

Whenever JavaScript executes the function3 function, a 'scope' object is created to hold the local variable named by you as a variable ("foo"). Note that your JavaScript code cannot directly access this scope object. And thus the value "foo" is available to the inner function, though the outer function has returned.

Does JavaScript traverse some kind of closure chain, similarly to how it traverses the prototype chain?

Yes. "Scope objects form a chain called the scope chain, similar to the prototype chain used by JavaScript's object system.

A closure is the combination of a function and the scope object in which it was created. Closures let you save state — as such, they can often be used in place of objects"

Read more here:

Community
  • 1
  • 1
enet
  • 41,195
  • 5
  • 76
  • 113
  • 1
    One thing I'm confused about is whether variable definitions are garbage collected when exiting a scope. I learned Ruby first, and I don't know if variables are garbage collected when you exit scope, but they behave like they are. Any clarification on whether `variable` is garbage collected and then re-instantiated when needed, or stored in memory even in global scope? – Wylliam Judd May 27 '16 at 21:18
  • "Whenever JavaScript executes a function, a 'scope' object is created to hold the local variables created within that function. It is initialized with any variables passed in as function parameters. This is similar to the global object that all global variables and functions live in, but" ... "a brand new scope object is created every time a function starts executing" OK, so that makes it sound like the variables are indeed garbage collected and re-instantiated when needed. In which case the block of memory that stores the anonymous function `function3` refers to must include its scope. – Wylliam Judd May 27 '16 at 21:40
  • @WylliamJudd The scope object that sticks around is the scope object of the _parent_ function (`function1` in your example), not the closure function itself. A new one is created at each execution for any local variables (including arguments) declared _within_ the function. If function1 returns two or more functions they will reference the same function1 scope object for their closure. – Random832 May 28 '16 at 01:07
2

Variables live in the scope where they are declared, which is either global or a function.

The keyword here is scope.

As explained brilliantly in the MSDN website:

A variable that is declared inside a function definition is local. It is created and destroyed every time the function is executed, and it cannot be accessed by any code outside the function. JavaScript does not support block scope (in which a set of braces {. . .} defines a new scope), except in the special case of block-scoped variables.

EDIT:

It is actually a little more complicated than this, see toddmotto's post about JS scopes.

Renato
  • 12,940
  • 3
  • 54
  • 85
  • 1
    I will copy this from toddmotto link as this is very relevant: `Scope chains establish the scope for a given function. Each function defined has its own nested scope as we know, and any function defined within another function has a local scope which is linked to the outer function - this link is called the chain. It’s always the position in the code that defines the scope. When resolving a variable, JavaScript starts at the innermost scope and searches outwards until it finds the variable/object/function it was looking for.` – Renato May 27 '16 at 20:38
  • "JavaScript does not support block scope (in which a set of braces {. . .} defines a new scope), except in the special case of block-scoped variables." What does that mean? The block inside of {. . .} defining `function1` is a local scope right? And outside that block is the global scope right? I don't get what this sentence is saying. – Wylliam Judd May 27 '16 at 20:42
  • "A variable that is declared inside a function definition is local. It is created and destroyed every time the function is executed, and it cannot be accessed by any code outside the function." Except that's not really true because of closure. `function3` exists entirely outside of `function1`, and yet it can access the variables defined in `function1`. The question is, how does it access that variable? Where does the variable live in the meantime? It's not defined in global scope. If I try to call variable in the global scope I get `ReferenceError: variable is not defined`. – Wylliam Judd May 27 '16 at 20:43
  • 2
    @WylliamJudd It's referring to things like `if` or `while` blocks... they don't have their own scope like most languages do. – Renato May 27 '16 at 20:44
  • 1
    @WylliamJudd function3 and function1 are just a reference to a single anonymous function... if you can see how they are just pointers to the anonymous functions, then you realize there's no visibility breaking going on here. – Renato May 27 '16 at 20:48
  • "It’s always the position in the code that defines the scope. When resolving a variable, JavaScript starts at the innermost scope and searches outwards until it finds the variable/object/function it was looking for." OK, that's really helpful. How does `function3` "know" that its scope is inside an outer scope? Since it's not actually defined inside `function1` where `variable` is defined... – Wylliam Judd May 27 '16 at 20:49
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/113181/discussion-between-renato-and-wylliam-judd). – Renato May 27 '16 at 20:50
1

The closure is decently explained on the MDN website. But I would recommend going through this awesome explanation in a Stack Overflow answer, a precise answer to your question.

It is not the property. Just that the environment is remembered in memory. Environment means function and the scope and scope members. I hope it enlightens the path.

Community
  • 1
  • 1
Aditya
  • 861
  • 5
  • 8
1

For an explanation on how closures work see this answer.

How do JavaScript closures work?

At the virtual machine level, every function has its own lexical environment which keeps track of this information. The virtual machine finds which variables are accessed in closures and stores them on the heap, and they live for as long as any closure might need them.

For more in-depth information see for example these two great pieces:

Community
  • 1
  • 1
VRPF
  • 3,118
  • 1
  • 14
  • 15