Execution Context, Lexical Environment, and Closures in JavaScript
Advanced JavaScript concepts you should know
In this piece I want to talk about three advanced JavaScript concepts: execution context, lexical environment, and closure.
This will be a long post. If you want to skip to the summary, scroll to the bottom of the page.
What is an Execution Context?
So, what is an execution context? Whenever you write some code, your code is in a space — that space is called the “execution context”. Imagine you wrote a simple calculator:
function cal(type, a, b) {
if (type === 'add') {
return a + b;
} else if (type === 'subtract') {
return a - b;
} else if (type === 'multiply') {
return a * b;
} else {
return a / b;
}
}
var four = 4;
var seven = 7;
cal('add', 4, 7);In JavaScript, whenever a function is invoked, a new execution context is created on the execution context currently running. A newly created one is stored in the stack for execution contexts.
So, if we call cal(), the new context will be created and it will be pushed to the context stack. But, by default, there’s an already existing context in the stack — a global execution context.

First the function cal is called and run so the new execution context is created. Then it is stored in the context stack. Then the control of the current execution context is transferred to the newly created one from, in this case, the global context.
An execution context is created whenever you call a function. When developing in JavaScript, you might have seen this error:

The function a keeps calling itself recursively. Every time a calls itself, a new execution context about a will be created and stored in the stack. Since the memory stack’s storage space isn’t infinite, it overflows.
Now you know what an execution context is, but there is more to learn. We’ll talk about it further shortly.
A Lexical Environment
What happens when you run a function or when you declare a variable or a function? I barely explained that an execution context is created on every function calls and there’s a global execution context in the stack by default. An execution context is divided into three different areas.

The first two sections in an execution context — LexicalEnvironment and VariableEnvironment, are very similar, so I think I can call them just LexicalEnvironment. What LexicalEnvironment does is to keep track of variables, function names and associated values. In other words, if you declare a function foo like a figure above, then the LexicalEnvironment would look like this:
function foo() {
var a = 10;
function bar() {
}
}
foo();
// When foo is called, a new execution environment
// might look like this below
execution_environment: {
LexicalEnvironment: {
a: 10,
bar: function() {}
},
ThisBinding: ...
}You now know what LexicalEnvironment is and what it does.
Just as an execution context consists of three parts, LexicalEnvironment also consists of a few parts. It has anEnvironmentRecord — I will call it an environment record, and an outer lexical environment that you may think it’s scope.
When you declare a variable or a function, they are actually stored in its environment record. Chaining the value of property basically means chaining the value of a property that belongs to an environment record.
A reference to the outer lexical environment is also created when LexicalEnvironment is created. It directly links to the parent LexicalEnvironment, and JavaScript uses this value when it can’t find a property in the current LexicalEnvironment. If it still can’t find it in the parent LexicalEnvironment, then it, again, goes up to the parent LexicalEnvironment. This process doesn’t stop until it finds what it’s looking for or until nothing is connected to the LexicalEnvironment. The global LexicalEnvironment doesn’t have a parent's LexicalEnvironment. So, when JavaScript tries to look for something in the global LexicalEnvironment, a Reference Error occurs.
Example with figures
To understand this flow better, let’s take a look at this example:
var x = 1;
function foo() {
var y = 2;
function bar() {
var z = 3;
function baz() {
console.log(z);
console.log(y);
console.log(x);
console.log(w);
}
baz();
}
bar();
}
foo();
// 3
// 2
// 1
// Reference Error: w is not defined
When JavaScript runs the code, the variable x and the function foo are declared in the global LexicalEnvironment. As I explained, the global’s outer doesn’t point to anything. When JavaScript meets foo() , it runs the function and the new LexicalEnvironment of foo is created. Its outer link links to its parent’s globalLexicalEnvironment. This figure illustrates the whole relationship in the example code:

You can see outer in each LexicalEnvironment points to the parent’s LexicalEnvironment.
When baz() is called, it looks for z, y , x , and w.

Like this flow, finding the variable y and x does the same work — checking whether or not to exist the value in the current LexicalEnvironment and moving to the parent’s one if there’s no variable. But for w , it doesn’t exist anywhere in the codes so we end up with a reference error.
This is what you normally heard, a scope chain. But remember, the outer environment, connecting to the parent’s environment, is determined when the function is declared, not when it’s invoked (Click here to get further information). For instance, guess the return value of bar().
var x = 1;
function foo() {
var x = 2;
bar();
}
function bar() {
console.log(x);
}
foo(); // 1Why is the result of foo() 1 and not 2? As I said, the outer reference is the parent’s LexicalEnvironment, not the function surrounding it.
ThisBinding
The reference inside the execution context, ThisBinding, determines how the function is called. I’ll talk about this topic more in another piece.
Back to Execution Context
Now, you know what are in an execution context — LexicalEnvironment and ThisBinding. There are actually two kinds of execution context — global execution context and function execution context.
The global execution context is the execution context for the global object in JavaScript, which is the root of everything. What it contains are several objects. One of them is window — when JavaScript parses and interprets your script, it actually runs this first. (Of course, this is not exactly how JavaScript works).
<script>
window = {
ClipboardCopyElement: class ClipboardCopyElement,
CodeMirror: f Ea,
DetailDialogElement: class DetailDialogElement,
...
};
GlobalExecutionContext: {
LexicalEnvironment: {
window: window,
outer: null
},
ThisBinding: window
}
</script>That’s why you could use window.document or window.setTimeout, since they are all in the LexicalEnvironment of the global object.
What about a function execution context? It’s just like a global execution context but no window or other global objects exist inside and it is created when a function is called. What the global execution context and function execution contexts have in common is that they both have two phases at runtime: creation and execution phases. In the creation phase, variables and functions are declared:
var x = 1;
function foo() {
var x = 2;
function bar() {
var x = 3;
}
}
console.log(y);
var y = 3;
foo();The first step on running the code is that the global execution context is created. The control of action is in the creation phase.

In the creation phase, variables are set by undefined by default. functions, on the other hand, are assigned by a function — like foo in the example above. The thing to note is that y is also defined as undefined as well, even though it’s declared after console.log . This symptom is called “hoisting” in JavaScript. Hoisting means variables and functions are declared and assigned with the default value, normally undefined , before the execution phase.
When the control moves to the execution phase, it runs every piece of code from the top. The first statement that will be executed is console.log(y) and it prints undefined out. Then y is set to three. The next step is to run foo(). When a function is called, a new execution context is created and pushed into the call stack.

When a function is called, a function execution context is made. Then its creation phase starts first. The LexicalEnvironment of the function execution context defines all of the variables it needs. The special object, arguments, is a part of variables that are defined in every function LexicalEnvironment. You can see there’s a function bar(). Then the bar is invoked — its execution context will also be stored in the stack after being created.
Once all of the codes in a function are executed, its execution context is removed from the stack.








