javascript
examples
examples.js⚡javascript
/**
* =====================================================
* 5.6 SCOPE AND CLOSURES - EXAMPLES
* =====================================================
* Understanding variable accessibility and closures
*/
// =====================================================
// 1. GLOBAL SCOPE
// =====================================================
console.log('--- Global Scope ---');
var globalVar = "I'm a global var";
let globalLet = "I'm a global let";
const globalConst = "I'm a global const";
function accessGlobals() {
console.log(globalVar); // Accessible
console.log(globalLet); // Accessible
console.log(globalConst); // Accessible
}
accessGlobals();
// =====================================================
// 2. FUNCTION SCOPE
// =====================================================
console.log('\n--- Function Scope ---');
function functionScopeDemo() {
var functionVar = "I'm function-scoped";
let functionLet = "I'm also inside function";
const functionConst = 'Me too';
console.log(functionVar); // ✅ Accessible inside
console.log(functionLet); // ✅ Accessible inside
console.log(functionConst); // ✅ Accessible inside
}
functionScopeDemo();
// console.log(functionVar); // ❌ ReferenceError
// =====================================================
// 3. BLOCK SCOPE
// =====================================================
console.log('\n--- Block Scope ---');
if (true) {
var blockVar = 'var is NOT block-scoped';
let blockLet = 'let IS block-scoped';
const blockConst = 'const IS block-scoped';
console.log('Inside block:', blockVar, blockLet, blockConst);
}
console.log('Outside block:', blockVar); // ✅ var leaks out
// console.log(blockLet); // ❌ ReferenceError
// console.log(blockConst); // ❌ ReferenceError
// =====================================================
// 4. BLOCK SCOPE IN LOOPS
// =====================================================
console.log('\n--- Loop Scope ---');
// var - shared across all iterations
console.log('Using var:');
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(' var i:', i), 10);
}
// Output: 3, 3, 3 (all see final value)
// let - unique per iteration
console.log('Using let:');
for (let j = 0; j < 3; j++) {
setTimeout(() => console.log(' let j:', j), 20);
}
// Output: 0, 1, 2 (each has own copy)
// =====================================================
// 5. HOISTING
// =====================================================
console.log('\n--- Hoisting ---');
// var is hoisted with undefined
console.log('hoistedVar:', typeof hoistedVar); // undefined
var hoistedVar = "I'm hoisted";
console.log('hoistedVar:', hoistedVar);
// let/const are in Temporal Dead Zone (TDZ)
// console.log(hoistedLet); // ReferenceError
let hoistedLet = 'I have TDZ';
// =====================================================
// 6. LEXICAL SCOPE
// =====================================================
console.log('\n--- Lexical Scope ---');
const outerVar = 'outer';
function outer() {
const outerFunctionVar = 'outer function';
function inner() {
const innerVar = 'inner';
// Can access all outer scopes
console.log(innerVar); // inner
console.log(outerFunctionVar); // outer function
console.log(outerVar); // outer
}
inner();
}
outer();
// =====================================================
// 7. SCOPE CHAIN
// =====================================================
console.log('\n--- Scope Chain ---');
const level0 = 'Global level';
function level1() {
const level1Var = 'Level 1';
function level2() {
const level2Var = 'Level 2';
function level3() {
const level3Var = 'Level 3';
// Can access all levels above
console.log(level3Var); // Level 3
console.log(level2Var); // Level 2
console.log(level1Var); // Level 1
console.log(level0); // Global level
}
level3();
}
level2();
}
level1();
// =====================================================
// 8. BASIC CLOSURE
// =====================================================
console.log('\n--- Basic Closure ---');
function createCounter() {
let count = 0; // Private variable via closure
return function () {
count++;
return count;
};
}
const counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3
// Each call creates independent closure
const counter2 = createCounter();
console.log(counter2()); // 1 (separate count)
// =====================================================
// 9. CLOSURE WITH MULTIPLE FUNCTIONS
// =====================================================
console.log('\n--- Closure with Multiple Functions ---');
function createCounterFull() {
let count = 0;
return {
increment() {
count++;
return count;
},
decrement() {
count--;
return count;
},
getCount() {
return count;
},
reset() {
count = 0;
return count;
},
};
}
const myCounter = createCounterFull();
console.log('Increment:', myCounter.increment()); // 1
console.log('Increment:', myCounter.increment()); // 2
console.log('Decrement:', myCounter.decrement()); // 1
console.log('Get count:', myCounter.getCount()); // 1
console.log('Reset:', myCounter.reset()); // 0
// =====================================================
// 10. DATA PRIVACY (ENCAPSULATION)
// =====================================================
console.log('\n--- Data Privacy ---');
function createBankAccount(initialBalance) {
let balance = initialBalance; // Private!
const transactions = []; // Private!
return {
deposit(amount) {
if (amount > 0) {
balance += amount;
transactions.push({ type: 'deposit', amount });
return balance;
}
return 'Invalid amount';
},
withdraw(amount) {
if (amount > 0 && amount <= balance) {
balance -= amount;
transactions.push({ type: 'withdraw', amount });
return balance;
}
return 'Insufficient funds';
},
getBalance() {
return balance;
},
getTransactions() {
return [...transactions]; // Return copy
},
};
}
const account = createBankAccount(100);
console.log('Initial:', account.getBalance()); // 100
account.deposit(50);
account.withdraw(30);
console.log('Final:', account.getBalance()); // 120
console.log('Transactions:', account.getTransactions());
// Cannot access directly
console.log('Direct access:', account.balance); // undefined
// =====================================================
// 11. FUNCTION FACTORY
// =====================================================
console.log('\n--- Function Factory ---');
function createMultiplier(multiplier) {
return function (number) {
return number * multiplier;
};
}
const double = createMultiplier(2);
const triple = createMultiplier(3);
const quadruple = createMultiplier(4);
console.log('double(10):', double(10)); // 20
console.log('triple(10):', triple(10)); // 30
console.log('quadruple(10):', quadruple(10)); // 40
// Greeting factory
function createGreeter(greeting) {
return function (name) {
return `${greeting}, ${name}!`;
};
}
const sayHello = createGreeter('Hello');
const sayHi = createGreeter('Hi');
console.log(sayHello('Alice')); // "Hello, Alice!"
console.log(sayHi('Bob')); // "Hi, Bob!"
// =====================================================
// 12. MEMOIZATION
// =====================================================
console.log('\n--- Memoization ---');
function memoize(fn) {
const cache = {};
return function (...args) {
const key = JSON.stringify(args);
if (cache[key] !== undefined) {
console.log(' Cache hit for', key);
return cache[key];
}
console.log(' Computing for', key);
const result = fn(...args);
cache[key] = result;
return result;
};
}
// Example: Fibonacci with memoization
const fibonacci = memoize(function (n) {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
});
console.log('fib(10):', fibonacci(10)); // Many computations
console.log('fib(10):', fibonacci(10)); // Cache hit!
console.log('fib(8):', fibonacci(8)); // Cache hit (computed during fib(10))
// =====================================================
// 13. MODULE PATTERN
// =====================================================
console.log('\n--- Module Pattern ---');
const Calculator = (function () {
// Private variables
let result = 0;
let history = [];
// Private function
function addToHistory(operation) {
history.push({ operation, result });
}
// Public API
return {
add(n) {
result += n;
addToHistory(`+ ${n}`);
return this;
},
subtract(n) {
result -= n;
addToHistory(`- ${n}`);
return this;
},
multiply(n) {
result *= n;
addToHistory(`* ${n}`);
return this;
},
getResult() {
return result;
},
getHistory() {
return [...history];
},
reset() {
result = 0;
history = [];
return this;
},
};
})();
Calculator.add(10).multiply(2).subtract(5);
console.log('Result:', Calculator.getResult()); // 15
console.log('History:', Calculator.getHistory());
// =====================================================
// 14. ONCE FUNCTION
// =====================================================
console.log('\n--- Once Function ---');
function once(fn) {
let called = false;
let result;
return function (...args) {
if (!called) {
called = true;
result = fn(...args);
console.log(' Function executed');
} else {
console.log(' Function already called');
}
return result;
};
}
const initialize = once((config) => {
return `Initialized with: ${JSON.stringify(config)}`;
});
console.log(initialize({ debug: true }));
console.log(initialize({ debug: false })); // Ignored, returns first result
// =====================================================
// 15. LOOP CLOSURE PROBLEM AND SOLUTIONS
// =====================================================
console.log('\n--- Loop Closure Problem ---');
// Problem with var
console.log('Problem with var:');
const functions1 = [];
for (var x = 0; x < 3; x++) {
functions1.push(function () {
return x;
});
}
console.log(functions1.map((fn) => fn())); // [3, 3, 3]
// Solution 1: let
console.log('Solution with let:');
const functions2 = [];
for (let x = 0; x < 3; x++) {
functions2.push(function () {
return x;
});
}
console.log(functions2.map((fn) => fn())); // [0, 1, 2]
// Solution 2: IIFE
console.log('Solution with IIFE:');
const functions3 = [];
for (var x = 0; x < 3; x++) {
(function (x) {
functions3.push(function () {
return x;
});
})(x);
}
console.log(functions3.map((fn) => fn())); // [0, 1, 2]
// =====================================================
// SUMMARY
// =====================================================
console.log('\n--- Summary ---');
console.log(`
SCOPE:
• Global - Top level, everywhere
• Function - Inside function only
• Block - Inside {} with let/const
DECLARATIONS:
• var - Function scope, hoisted
• let - Block scope, TDZ
• const - Block scope, TDZ, immutable
CLOSURES:
• Function + lexical environment
• Remembers outer variables
• Enables data privacy
• Use for factories, memoization, modules
`);