Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Closures and ES2015

I apologize in advance for yet another closure question, but I'd like to clarify my understanding of the way closures are implemented in JavaScript.

Consider the following code:

01 'use strict';
02 function foo() {}
03 foo();

I have established in a question earlier in the year that a closure is conceptually (if not actually due to engine optimizations) created here.

And until foo is invoked on line 3 a corresponding execution context is not created.

So as far as I can tell from the spec, when evaluating this code:

  1. Each execution context has a "LexicalEnvironment" component used to resolve identifier references made by code within it (8.3, Table 23).
  2. FunctionCreate is called, passing in a reference (named "scope") to the "LexicalEnvironment" component of the current execution context. (14.1.19)
  3. FunctionCreate calls FunctionInitialize passing "scope" (9.2.5)
  4. FunctionInitialize ensures that the [[Environment]] internal slot of the function-object being created is set to the value of "scope" (the reference to the "LexicalEnvironment" component of the current execution context) (9.2.4)

Finally, when foo is actually invoked, I find the spec harder to interpret.

  1. In PrepareForOrdinaryCall, the "LexicalEnvironment" of the new execution context for the call is set to be the result of calling NewFunctionEnvironment (9.2.1.1)
  2. NewFunctionEnvironment copies the reference to the "LexicalEnvironment" component of the outer execution context (the [[Environment]] slot of the function-object) into the Environment record (EnvironmentRecord?) of the "LexicalEnvironment" component of the execution context under construction as the "outer lexical environment reference" (8.1.2.4)

Thus closures are implemented in a two step fashion:

  1. A linkage between function-object and the enclosing "LexicalEnvironment" of the enclosing execution context, is created at function-object instantiation time. This is the [[Environment]] internal slot of the function-object.
  2. When a function is invoked, this reference to the enclosing "LexicalEnvironment" component of the outer execution context (the contents of the [[Environment]] slot of the function object) is copied into a spec-imprecisely-defined(?)/EnvironmentRecord(?) sub-component of the "LexicalEnvironment" component of the new execution context.

Does this sound about right?

like image 495
Ben Aston Avatar asked Feb 02 '26 12:02

Ben Aston


1 Answers

Does this sound about right?

Pretty much. I just wouldn't use the work "copied", rather "linked". To simplify it a little:

  1. When a function is created, it stores are reference to the environment it was created it.
  2. When the function is executed, this stored environment becomes the "outer environment" of the newly created function environment.

Or in pictures:

                  +----------------+                     +----------------+
   Function       |                |   [[Environment]]   |     Outer      |
   creation       |    Function    |-------------------->|  Environment   |
                  |                |                     |                |
                  +----------------+                     +----------------+
                                                                  ^        
                                                                  |        
                                                                  |        
                  +----------------+                              |        
   Function       |    Function    |  outer environment reference |        
   execution      |  Environment   |------------------------------+        
                  |                |                                       
                  +----------------+                                       

This happens to every function and depending on your definition of closure1, this makes every function a closure (or not).


1: I believe there are these two takes on what it means for a function to be a closure:

  • If a function stores a references to the environment it was created in, it's a closure (applies to every function in JS)
  • If a function stores a reference to the environment it was created in and "leaves" that environment (the environment "ceases to exist"), it's a closure. That's of course not always the case.
like image 98
Felix Kling Avatar answered Feb 04 '26 00:02

Felix Kling



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!