In JavaScript, every running function, code block {...}, and the script as a whole have an internal (hidden) associated object known as the Lexical Environment.
The Lexical Environment object consists of two parts:
(1) In this simple code without functions, there is only one Lexical Environment. This is the so-called global Lexical Environment, associated with the whole script.
(2)
A Function Declaration is instantly fully initialized.
When the code wants to access a variable – the inner Lexical Environment is searched first, then the outer one, then the more outer one and so on until the global one.
All functions remember the Lexical Environment in which they were made. All functions have the hidden property named [[Environment]]
, that keeps the reference to the Lexical Environment where the function was created.
[[Environment]]
has the reference to {count: 0} Lexical Environment. That’s how the function remembers where it was created, no matter where it’s called. The [[Environment]]
reference is set once and forever at function creation time.A closure is a function that remembers its outer variables and can access them. They automatically remember where they were created using a hidden
[[Environment]]
property, and then their code can access outer variables.
Usually, a Lexical Environment is removed from memory with all the variables after the function call finishes. That’s because there are no references to it. As any JavaScript object, it’s only kept in memory while it’s reachable.
But if there’s a nested function that is still reachable after the end of a function, then it has [[Environment]]
property that references the lexical environment.
In that case the Lexical Environment is still reachable even after the completion of the function, so it stays alive.
function f() {
let value = 123;
return function() {
alert(value);
}
}
let g = f(); // while g function exists, the value stays in memory
g = null; // now the memory is cleaned up