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.
tl;dr:
In the environment it was defined in.
No.
Yes.
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):
The global environment doesn't have any outer environment because it is at the top.
function1
andfunction3
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: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. callingfunction2
. 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: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 offunction1
's[[Environment]]
field. This is were the scope chain is created.Now, after executing
function1
, the memory has this structure:Similar like
function1
,function2
has a reference to the environment created by callingfunction2
. In addition,function3
refers to the function we created because we return it fromfunction1
.Last step: calling
function3('bar')
: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 upvariable
, 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.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:
EDIT:
It is actually a little more complicated than this, see toddmotto's post about JS scopes.
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:
Grokking V8 closures for fun (and profit?)
How do JavaScript closures work under the hood
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.
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.
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: