Deep Dive JavaScript Mastery
Execution Contexts
How JavaScript Runs Code
When you run JavaScript code, it doesn't just execute from top to bottom instantly. The JavaScript engine first creates a special environment to manage and run your code. This environment is called an Execution Context and acts as a container holding all the necessary information for your code to run properly.
Every line of JavaScript runs inside an Execution Context — this is the foundation of how JS works.
Think of it like a chef preparing to cook. Before they start chopping vegetables, they first gather all the ingredients, utensils, and check the recipe. This preparation is a distinct phase from the actual cooking.
Similarly, every Execution Context has two phases: the Creation Phase and the Execution Phase.
The Global Context
The very first Execution Context created is the Global Execution Context (GEC). This is the base-level context that wraps all of your code. Let's see what happens during its two phases.
Creation Phase: The engine scans your entire script before executing a single line. It's looking for variable and function declarations.
During this initial scan, the engine does three key things:
- Creates the Global Object: In a web browser, this is the
windowobject. - Creates the
thiskeyword: In the global context,thisis set to point to the Global Object (window). - Sets up memory for variables and functions: This process is called hoisting and it's why you can sometimes use a function before you've declared it. The engine allocates memory for all function declarations and variable declarations.
For var, the variable is declared and initialized with a value of undefined. For let and const, the variables are declared but left uninitialized, creating what's known as the Temporal Dead Zone. You can't access them until the execution phase reaches their declaration.
Execution Phase: After the preparation is done, the engine executes your code line by line. It's during this phase that variables are assigned their actual values.
// Global Scope
console.log(myVar); // logs 'undefined' because of hoisting
console.log(sayHello); // logs the function definition
var myVar = 'Hello, World!';
function sayHello() {
console.log('Hello');
}
console.log(myVar); // logs 'Hello, World!'
Function Contexts and the Stack
Things get more interesting when you call a function. Every time a function is invoked, a brand new Function Execution Context is created. This new context is stacked on top of the current one, forming what's called the Execution Stack or Call Stack.
The context at the top of the stack is the one currently running. When it finishes, it's popped off the stack, and control returns to the context below it.
A Function Execution Context's creation phase is slightly different. It creates an Activation Object (or Variable Object) that holds:
- An
argumentsobject, which is an array-like list of all parameters passed to the function. - Named parameters, which are treated as local variables.
- All local variable and function declarations within the function (hoisting again!).
Crucially, this is also when the Scope Chain is formed. The function's context gets a reference to its outer environment's variables. If the engine can't find a variable in the current function's context, it follows this link to the outer context and looks there. This chain continues all the way up to the Global Execution Context.
This link to the outer environment is determined by where the function is physically written in the code, not by where it is called. This principle is called Lexical Scoping.
var globalVar = 'I am global';
function outerFunc() {
var outerVar = 'I am outer';
function innerFunc() {
// Can access outerVar and globalVar
// through the scope chain.
console.log(outerVar + ' and ' + globalVar);
}
innerFunc();
}
outerFunc(); // logs 'I am outer and I am global'
In this example, when innerFunc is executed, it first looks for outerVar in its own Activation Object. Not finding it, it follows the scope chain to outerFunc's context, where it finds the variable. It does the same for globalVar, following the chain all the way to the GEC.
What is the environment that the JavaScript engine creates to manage and run your code called?
What are the two distinct phases of an Execution Context?