This content originally appeared on DEV Community and was authored by Jacin Yan
What are closures and where do they come from?
A couple sources of information might 'somewhat' has an answer to the questions:
- A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives you access to an outer function’s scope from an inner function. In JavaScript, closures are created every time a function is created, at function creation time. -- MDN
- Closures are created when functions are defined in other functions, allowing the closure access to all of the variables inside of the containing function. -- Professional JavaScript for Developers
- Closure builds on this approach: for variables we need to use over time, instead of placing them in larger outer scopes, we can encapsulate (more narrowly scope) them but still preserve access from inside functions, for broader use. Functions remember these referenced scoped variables via closure. -- You don't know JS
I agree that the statements above may still sound like gibberish. On top of that, I might have some different opinions as to whether or not they are acccurat enough, so before going further we can probably take a look at the 'lexical environment' bit. I'll start with one property.
[[Environment]]
From what I've learned so far, [[Environment]]
is an internal property and:
- Every function has this property
- It serves the purpose of storing a reference to the the lexical environment in which the fucntion is created (There's the ambiguity. My understanding is that it should be when an function instance is created, simply speaking, when it is called, rather than when it is defined)
- It can not be manipulated directly
(Another internal prop we might be more familiar with is [[Prototype]])
Lexcial environment object
So what exactly is this lexical environment that [[Environment]]
refences?
It is essentially an object, and note that:
Before a script is executed/run, one lexical environment object will be created, which is at the global lexical environment.
Whenever a function is being executed/run, one lexical environment will be created, which is at a function level
You might be wondering, what does this the object contain? Well, it bascially contains two things:
A record/snapshot of the current environment, where all the identfiers (a variable name, a function name etc.) and what they are referencing become its key-value pairs
A reference to its outer lexical environment
Now we run into something interesting. From the second part, we know that:
The [[Environment]]
prop of one certain function keeps track of the function's own lexical environment, and this lexical enviornment keeps track of its outer lexical environment, so far and so forth, all the way up to the global lexical environment. Do you see that there is essentially a linked list, which is something we've probaly heard a thousand times, a scope chain.
To see things more clearly, I'll demonstrate with some code
For example,
function foo() {
const a = 1;
function bar() {
console.log('hi')
}
}
foo()
//`[[Environment]]` of `foo` is referecing 'something'(a lexical environment' that has:
//1. Current environment record:
//a:1, bar: ()=>console.log('hi')
//2. A refrence to its outer lexical environment
//(which happens to be the global lexical environment in this case)
Functions bundled with lexical environments
We know from previously that a closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). However, something I have yet to mention is that, each function instance is dependent of each other, and therefore their own lexical environment. In addition, there's a term called 'free variables' in functional programming, which means variables appear in one particular environment but are never defined in it. From clousres' point of view, it simply means a variable in the outer function is being refenced by an inner function. Whenever that happens, the JS engine will go all the way up the scope chain to search for it. There's two possible outcomes, one of which is that it spits out 'ReferenceError, xxxx is not defined'. Another is that the engine is able to pinpoint them, and after the execution of the outer function the free variables and the values they have been referencing still remain(From what I know, they are stored yet again as key-value pairs in a place where we also don't have direct access to)
An example:
function baz() {
let a = 1;
return function qux() {
console.log(a++)
}
}
let x = baz()//The return value of `baz()`, which is a function, is still being referenced, in this case by a global variable `x`
x();//1
x();//2
//The following executions essentially create two independent function instances:
// After the first return value of `baz()` is executed, the idetifiers `a` and `qux` respectively will be garge collected since they are not referencing anything anymore
// The same goes for the second one, in that everything is brand new and therefore it doesn't stop it from logging `a = 1` again
baz()()//1
baz()()//1
Interestingly, what if we don't have this 'lexical environment' ? Let's go back to the example above but this time think about what would happen, along with the execution context (call stack)
-
baz()
is pushed into the stack, and then variablea
is pushed into the stack; -
a
is popped out of the stack, and then so isbaz()
- When
x()
is pushed into the stack, here comes the problem. During the execution ofx()
, it is looking fora
, but there's just no way that it can be found anywhere. Obviously, this is against our expectations.
'The bundle of functions and lexical environments, when closures are generated' comes to the rescue
(To be continued....)
Garbage collection in JS
(To be continued....)
This content originally appeared on DEV Community and was authored by Jacin Yan
Jacin Yan | Sciencx (2021-10-23T10:11:26+00:00) [[Environment]], closures and garbage collection. Retrieved from https://www.scien.cx/2021/10/23/environment-closures-and-garbage-collection/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.