Execution Context is a fundamental concept in JavaScript that defines the environment in which JavaScript code is executed. It contains information about variable scope, this binding, and much more.
Types of Execution Context
1. Global Execution Context (GEC)
// This is in Global Execution Context
let name = "John";
console.log(this); // Window object (in browser)2. Function Execution Context (FEC)
function greet() {
// This is Function Execution Context
let message = "Hello";
console.log(message);
}3. Eval Execution Context
Created when code is executed inside an eval function (rarely used in modern JavaScript).
Phases of Execution Context
1. Creation Phase (Memory Creation)
During this phase:
- Variables are allocated memory and initialized with
undefined - Function declarations are stored in memory
thisbinding occurs
console.log(name); // undefined (not error)
var name = "John";
sayHello(); // Works due to hoisting
function sayHello() {
console.log("Hello!");
}2. Execution Phase
During this phase:
- Code is executed line by line
- Variable assignments are done
- Function calls create new execution contexts
var name = "John"; // Value assigned
console.log(name); // "John"Execution Context Stack (Call Stack)
How it Works
function first() {
console.log("First");
second();
}
function second() {
console.log("Second");
third();
}
function third() {
console.log("Third");
}
first();Stack Operation:
- Global Execution Context
- First() pushed
- Second() pushed
- Third() pushed
- Third() popped
- Second() popped
- First() popped
Scope Chain
Example of Scope Chain
let globalVar = "I'm global";
function outer() {
let outerVar = "I'm from outer";
function inner() {
let innerVar = "I'm from inner";
console.log(innerVar); // Local scope
console.log(outerVar); // From outer scope
console.log(globalVar); // From global scope
}
inner();
}
outer();Variable Environment
Let vs Var vs Const
{
var x = 1; // Function scoped
let y = 2; // Block scoped
const z = 3; // Block scoped
}
console.log(x); // 1
console.log(y); // ReferenceError
console.log(z); // ReferenceErrorLexical Environment
function outer() {
let count = 0;
return function inner() {
count++; // Has access to outer function's variables
return count;
}
}
const increment = outer();
console.log(increment()); // 1
console.log(increment()); // 2This Binding
Different Contexts
// Global Context
console.log(this); // Window (browser)
// Object Method
const obj = {
name: "Object",
sayName() {
console.log(this.name);
}
};
// Constructor Function
function Person(name) {
this.name = name;
}
// Event Handler
button.addEventListener('click', function() {
console.log(this); // button element
});Practical Examples
1. Closure with Execution Context
function createCounter() {
let count = 0; // Part of createCounter's execution context
return {
increment() {
return ++count;
},
decrement() {
return --count;
}
};
}
const counter = createCounter();
console.log(counter.increment()); // 1
console.log(counter.increment()); // 2
console.log(counter.decrement()); // 12. Block Scoping Example
function example() {
let x = 10;
if(true) {
let y = 20; // Block scoped
var z = 30; // Function scoped
console.log(x); // 10 - accessible
}
console.log(z); // 30 - accessible
console.log(y); // ReferenceError - not accessible
}Best Practices
- Always declare variables with appropriate scope
// Bad
function bad() {
x = 10; // Global variable!
}
// Good
function good() {
let x = 10; // Local variable
}- Use block scope when possible
// Prefer
for(let i = 0; i < 5; i++) {
// i is block scoped
}
// Instead of
for(var i = 0; i < 5; i++) {
// i is function scoped
}- Be mindful of
thiscontext
const obj = {
name: "Object",
greet: () => {
// Arrow functions don't bind their own this
console.log(this.name); // undefined
},
greetProperly() {
console.log(this.name); // "Object"
}
};Understanding execution context is crucial for:
- Debugging code
- Understanding scope
- Managing variable lifecycles
- Writing more efficient code
- Avoiding common pitfalls in JavaScript