javascript
examples
examples.js⚡javascript
/**
* ============================================
* 6.1 EXECUTION CONTEXT - EXAMPLES
* ============================================
*/
/**
* EXAMPLE 1: Global Execution Context
* ------------------------------------
* When JavaScript starts, it creates the Global EC
*/
// These are in the Global Execution Context
var globalVar = "I'm a global variable";
let globalLet = "I'm also global but not on window";
const globalConst = "I'm a global constant";
function globalFunction() {
return "I'm a global function";
}
// In browsers, var and functions attach to window
console.log('=== Global Execution Context ===');
console.log('globalVar:', globalVar);
console.log('globalFunction:', globalFunction());
// Check if we're in browser or Node
if (typeof window !== 'undefined') {
console.log('window.globalVar:', window.globalVar);
console.log('window.globalLet:', window.globalLet); // undefined!
}
/**
* EXAMPLE 2: Function Execution Context
* -------------------------------------
* New EC created each time a function is CALLED
*/
console.log('\n=== Function Execution Context ===');
function createMessage(name) {
// New FEC created here with:
// - arguments: { 0: name, length: 1 }
// - name: (parameter value)
// - greeting: undefined → "Hello"
// - this: global/undefined
var greeting = 'Hello';
return greeting + ', ' + name + '!';
}
console.log(createMessage('Alice')); // FEC created
console.log(createMessage('Bob')); // Another FEC created
/**
* EXAMPLE 3: Creation Phase - Hoisting
* ------------------------------------
* Variables and functions are set up before code runs
*/
console.log('\n=== Creation Phase (Hoisting) ===');
// This works because of the creation phase
console.log('sayHello exists:', typeof sayHello); // "function"
sayHello(); // Works!
function sayHello() {
console.log('Hello from hoisted function!');
}
// var is hoisted but undefined
console.log('myVar before assignment:', myVar); // undefined
var myVar = 'Now I have a value';
console.log('myVar after assignment:', myVar); // "Now I have a value"
/**
* EXAMPLE 4: Execution Phase
* --------------------------
* Code runs line by line
*/
console.log('\n=== Execution Phase ===');
function calculate(a, b) {
// Creation Phase:
// - a: 5, b: 3
// - result: undefined
// - doubled: undefined
// Execution Phase:
console.log('Step 1: result is', typeof result); // undefined
var result = a + b;
console.log('Step 2: result is', result); // 8
var doubled = result * 2;
console.log('Step 3: doubled is', doubled); // 16
return doubled;
}
calculate(5, 3);
/**
* EXAMPLE 5: Nested Execution Contexts
* ------------------------------------
* Each function call creates its own context
*/
console.log('\n=== Nested Execution Contexts ===');
function outer(x) {
var outerVar = 'outer: ' + x;
console.log('In outer, outerVar =', outerVar);
function inner(y) {
var innerVar = 'inner: ' + y;
console.log('In inner, innerVar =', innerVar);
console.log('In inner, can access outerVar =', outerVar);
}
inner(x * 2);
}
outer(5);
/**
* EXAMPLE 6: Variable Environment vs Lexical Environment
* -------------------------------------------------------
* var vs let/const behavior
*/
console.log('\n=== Variable Environment vs Lexical Environment ===');
function demonstrateEnvironments() {
// var: stored in Variable Environment
// Hoisted and initialized to undefined
console.log('varVariable before:', varVariable); // undefined
var varVariable = "I'm var";
console.log('varVariable after:', varVariable);
// let/const: stored in Lexical Environment
// Hoisted but NOT initialized (Temporal Dead Zone)
// console.log("letVariable before:", letVariable); // ReferenceError!
let letVariable = "I'm let";
console.log('letVariable after:', letVariable);
}
demonstrateEnvironments();
/**
* EXAMPLE 7: Temporal Dead Zone
* -----------------------------
* The zone where let/const exist but can't be accessed
*/
console.log('\n=== Temporal Dead Zone ===');
function tdzExample() {
// TDZ starts for 'myLet' and 'myConst'
// This would throw ReferenceError:
// console.log(myLet);
console.log("Before let declaration - can't access myLet");
let myLet = 'Now accessible';
// TDZ ends for myLet
console.log('After let declaration:', myLet);
const myConst = 'Constant value';
console.log('After const declaration:', myConst);
}
tdzExample();
/**
* EXAMPLE 8: Scope Chain Through Execution Contexts
* -------------------------------------------------
* How variables are looked up
*/
console.log('\n=== Scope Chain ===');
var globalName = 'Global';
function levelOne() {
var levelOneName = 'Level One';
function levelTwo() {
var levelTwoName = 'Level Two';
function levelThree() {
var levelThreeName = 'Level Three';
// Can access all outer scopes
console.log('From levelThree:');
console.log(' levelThreeName:', levelThreeName);
console.log(' levelTwoName:', levelTwoName);
console.log(' levelOneName:', levelOneName);
console.log(' globalName:', globalName);
}
levelThree();
}
levelTwo();
}
levelOne();
/**
* EXAMPLE 9: Each Call Gets Its Own Context
* -----------------------------------------
* Same function, different contexts
*/
console.log('\n=== Separate Execution Contexts ===');
function counter(id) {
var count = 0;
count++;
console.log(`Counter ${id}: count = ${count}`);
return count;
}
// Each call has its own 'count' variable
counter('A'); // count = 1
counter('B'); // count = 1 (not 2!)
counter('C'); // count = 1 (still independent)
/**
* EXAMPLE 10: this in Execution Context
* -------------------------------------
* 'this' is determined at context creation
*/
console.log("\n=== 'this' Binding ===");
// Global context
console.log("Global 'this':", this === globalThis); // true in most environments
const myObject = {
name: 'MyObject',
regularMethod: function () {
// 'this' = myObject (determined by how it's called)
console.log("Regular method 'this'.name:", this.name);
},
arrowMethod: () => {
// 'this' = lexical 'this' (from where arrow was defined)
console.log("Arrow method 'this':", this);
},
};
myObject.regularMethod(); // "MyObject"
myObject.arrowMethod(); // global object or undefined
/**
* EXAMPLE 11: Hoisting Order of Precedence
* ----------------------------------------
* Functions are hoisted before variables
*/
console.log('\n=== Hoisting Precedence ===');
function hoistingTest() {
console.log('typeof myFunc:', typeof myFunc); // "function" (not undefined)
var myFunc = "I'm a string now";
function myFunc() {
return "I'm a function";
}
console.log('typeof myFunc:', typeof myFunc); // "string"
}
hoistingTest();
/**
* EXAMPLE 12: Arguments Object in Function EC
* -------------------------------------------
* The arguments object is created in the creation phase
*/
console.log('\n=== Arguments Object ===');
function showArguments(a, b, c) {
console.log('Named parameters:', a, b, c);
console.log('arguments object:', arguments);
console.log('arguments.length:', arguments.length);
console.log('arguments[0]:', arguments[0]);
// arguments is array-like but not an array
console.log('Is array:', Array.isArray(arguments)); // false
}
showArguments(1, 2, 3);
showArguments('x', 'y'); // c will be undefined
/**
* EXAMPLE 13: Closure and Execution Context
* -----------------------------------------
* Closures remember their creation context
*/
console.log('\n=== Closure and Execution Context ===');
function createGreeter(greeting) {
// This execution context is "remembered"
return function (name) {
// New EC, but has reference to outer EC
return `${greeting}, ${name}!`;
};
}
const sayHi = createGreeter('Hi');
const sayHowdy = createGreeter('Howdy');
// createGreeter's EC is gone, but closure remembers 'greeting'
console.log(sayHi('Alice')); // "Hi, Alice!"
console.log(sayHowdy('Bob')); // "Howdy, Bob!"
/**
* EXAMPLE 14: Debugging with Execution Context Knowledge
* ------------------------------------------------------
* Understanding why common bugs happen
*/
console.log('\n=== Common Bugs Explained ===');
// Bug 1: Accessing before declaration
function bug1() {
console.log('accessingVar:', accessingVar); // undefined, not error
var accessingVar = 'value';
// Why? Creation phase hoists var to undefined
}
bug1();
// Bug 2: Loop variable issue (classic)
function bug2() {
var funcs = [];
for (var i = 0; i < 3; i++) {
funcs.push(function () {
return i; // All return 3!
});
}
console.log(
'With var:',
funcs.map((f) => f())
); // [3, 3, 3]
// Why? Only one 'i' in the function's execution context
}
bug2();
// Fix: Use let (block-scoped)
function bug2Fixed() {
var funcs = [];
for (let i = 0; i < 3; i++) {
funcs.push(function () {
return i;
});
}
console.log(
'With let:',
funcs.map((f) => f())
); // [0, 1, 2]
// Why? New 'i' for each iteration's block scope
}
bug2Fixed();
/**
* EXAMPLE 15: Strict Mode and Execution Context
* ---------------------------------------------
* Strict mode affects 'this' binding
*/
console.log("\n=== Strict Mode and 'this' ===");
function nonStrict() {
console.log("Non-strict 'this':", typeof this); // object (global)
}
function useStrict() {
'use strict';
console.log("Strict 'this':", this); // undefined
}
nonStrict();
useStrict();
console.log('\n=== End of Examples ===');