Sep 27, 2025

JavaScript Execution Context Explained: Compilation vs Runtime with Practical Examples

JavaScript may look straightforward when reading code, but under the hood, the JavaScript engine runs your code inside a special environment called the execution context. This is where all the magic happens — variables are created, functions are set up, and the actual running of your code takes place.


Before jumping into how your JavaScript plays out, it’s key to understand that execution happens in two distinct phases: the compilation (or creation) phase and the runtime (or execution) phase.


What is Execution Context?


Think of execution context as a container or environment where your JavaScript code runs. Each JS program and each function call gets its own execution context. These contexts keep track of variable declarations, function declarations, scope, and the value of this.


JavaScript starts with a Global Execution Context for your entire script. Whenever a function is called, a new Function Execution Context is created and pushed onto the call stack. JavaScript runs in a single thread, meaning only one execution context runs at a time.


Two Phases of Execution Context


1. Compilation (Creation) Phase


Before any code runs, the JS engine scans the code and prepares the environment:

  • Memory Allocation: The engine sets aside memory for variables and functions declared in the current scope.
  • Hoisting: Variables declared with var are placed in memory with an initial value of undefined. Functions are fully hoisted with their definitions.
  • Temporal Dead Zone Setup: Variables declared with let and const are noted but not initialised yet — they enter a Temporal Dead Zone until actual declaration.
  • Scope Chain Setup: JS determines variable accessibility starting with the current context and moving outward to parent contexts.
  • this keyword assignment happens according to the context (global object or function owner).


Because of this setup, variables and functions can sometimes be referenced before their declaration in your code without causing runtime errors (this is why hoisting exists).


2. Runtime (Execution) Phase


Once the environment is ready, JavaScript starts running your code line by line, performing:

  • Variable assignments and updates.
  • Function invocations.
  • Expression evaluations.
  • Handling errors when trying to use uninitialized let/const variables within the Temporal Dead Zone.

Code Example Demonstrating Phases


Explanation:

  • During compilation, a is hoisted and initialised to undefined. b is hoisted but not initialised (TDZ). foo function is fully hoisted and ready. bar variable is hoisted as undefined.
  • During runtime, console.log(a) prints undefined. Trying to log b before declaration causes ReferenceError (due to TDZ).
  • Calling foo() works because the function is hoisted with its definition.
  • Calling bar() fails because only the variable declaration is hoisted, not the function assignment.


Why Understanding These Phases Matters


When you clearly understand how the compilation and execution phases work inside the execution context, many JavaScript quirks become obvious:
  • Why hoisting allow some code to run despite the order?
  • Why let and const create the Temporal Dead Zone that throws errors if accessed early?
  • Why function declarations are hoisted but function expressions behave differently.
  • How scope chains and this are resolved.
This foundational knowledge is crucial for writing bug-free, predictable code and debugging tricky behaviours efficiently.


EmoticonEmoticon