JavaScript code runs in a structured environment known as the execution context. This concept is key to understanding how variables, functions, and the scope chain behave in JavaScript. When you grasp how JavaScript creates and manages execution contexts, you'll write more predictable and bug-free code.
What is Execution Context in JavaScript?
An execution context is the environment in which JavaScript code is evaluated and executed. It contains details about the currently running code, such as variables, functions, and the value of this.
Types of Execution Context
- Global Execution Context (GEC):
Created by default when JavaScript starts executing. Variables and functions declared outside any function live here. - Function Execution Context (FEC):
Created each time a function is called. Every call has its own context. - Eval Execution Context:
Created by theeval()function (rarely used and not recommended).
Phases of Execution Context
Each execution context runs through two main phases:
Creation Phase
- Allocates memory for variables and functions.
- Variables are initialized with
undefined. - Functions are hoisted into memory.
- Scope chain and
thisare defined.
Execution Phase
- Code executes line by line.
- Variables are assigned actual values.
- Functions are invoked.
How JavaScript Handles Memory in Each Phase
JavaScript processes code in two phases: Creation and Execution. During these phases, it allocates memory and runs code line by line.
Example:
var name = "Aman";
function sayHello() {
var greeting = "Hello, " + name;
console.log(greeting);
}
sayHello();
Global Execution Context
Creation Phase:
| Identifier | Value |
|---|---|
name
| undefined
|
sayHello
| function(){...}
|
Execution Phase:
| Identifier | Value |
|---|---|
name
| "Aman"
|
sayHello
| function(){...}
|
sayHello Execution Context
Creation Phase:
| Identifier | Value |
|---|---|
greeting
| undefined
|
Execution Phase:
| Identifier | Value |
|---|---|
| greeting | "Hello, Aman" |
Output:
Hello, Aman
nameis accessed from the global scope.console.log(greeting)prints the output.
The Execution Stack (Call Stack)
JavaScript uses a call stack (also called execution stack) to manage execution contexts. When a function is called, its execution context is pushed onto the stack. When the function finishes, it's popped off the stack.
Example:
function start() {
console.log("Start");
process();
console.log("End");
}
function process() {
console.log("Processing...");
complete();
}
function complete() {
console.log("Complete");
}
start();
Execution Order:
- Global context is created.
start()is called → its context is pushed to the stack.- Inside
start(),process()is called → new context pushed. - Inside
process(),complete()is called → new context pushed. complete()runs and is popped off.process()finishes and is popped off.start()finishes and is popped off.
Output:
Start
Processing...
Complete
End
This stack-based execution ensures functions are completed in a last-in, first-out manner.
Execution Context Example with Nested Functions
var city = "Delhi";
function showCity() {
var landmark = "India Gate";
function display() {
console.log(city); // Accesses from global context
console.log(landmark); // Accesses from showCity() context
}
display(); // Execution context for display()
}
showCity(); // Execution context for showCity()
- Each function gets its own execution context.
- Lexical scoping allows inner functions to access variables from outer contexts.
Explanation:
- Global context holds
cityandshowCity. - When
showCity()runs, a new context is created. display()accesses bothcityandlandmarkdue to lexical scoping.- JavaScript uses the scope chain to look up variables from outer contexts.
How JavaScript Handles Hoisting
In the creation phase, JavaScript hoists declarations to the top of their scope.
Example:
console.log(age); // undefined due to hoisting
var age = 25;
ageis hoisted asundefined.- Value
25is assigned during the execution phase.
Function Declarations (Hoisted Fully)
greet(); // Works due to hoisting
function greet() {
console.log("Hello!");
}
Function Expressions (Not Hoisted)
sayHello(); // TypeError
var sayHello = function() {
console.log("Hi!");
};
Key Takeaways
- Execution context defines how JavaScript runs your code.
- It goes through creation and execution phases.
- JavaScript uses a call stack to manage execution order.
- Variable and function declarations are hoisted in the creation phase.
- A strong grasp of context helps avoid scope and hoisting issues.
Conclusion
In this tutorial, you learned how JavaScript runs code using execution contexts, which go through a creation phase for memory allocation and an execution phase for running logic. You explored the global and function contexts, understood hoisting behavior, and saw how the call stack manages the order of execution. By visualizing memory step by step, you now better understand how JavaScript handles variables, functions, and scope during code execution.