Exercise

Variable shadowing occurs when a variable declared in an inner scope has the same name as a variable in an outer scope. The inner variable "shadows" the outer one within its scope.

javascript

var name = 'global';

function greet() {
    var name = 'local'; // shadows the global 'name'
    console.log(name);  // Output: local
}
greet();
console.log(name); // Output: global

The Temporal Dead Zone (TDZ) is the period between entering a scope and the point where a let or const variable is declared. Accessing the variable during this period throws a ReferenceError.

javascript

// TDZ starts here for 'x'
console.log(x); // ReferenceError: Cannot access 'x' before initialization
let x = 5;      // TDZ ends here

A closure is a function that has access to its outer function's variables even after the outer function has returned. The inner function "closes over" the variables in the outer scope, keeping them alive.

javascript

function makeCounter() {
    let count = 0;
    return function() {
        count++;
        return count;
    };
}

const counter = makeCounter();
console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3

A closure is created when an inner function retains access to variables from its lexical (outer) scope even after the outer function has finished executing. The closure keeps the scope chain alive.

javascript

function outer() {
    var secret = 42;
    return function inner() {
        // inner has a closure over 'secret'
        console.log(secret);
    };
}

const revealSecret = outer();
revealSecret(); // Output: 42 — outer's scope is preserved

Variables declared with var inside a block (if, for, etc.) are not block-scoped. They are hoisted to the enclosing function scope (or global scope), making them accessible outside the block.

javascript

if (true) {
    var blockVar = 'I am var';
    let blockLet = 'I am let';
}
console.log(blockVar); // Output: I am var
console.log(blockLet); // ReferenceError: blockLet is not defined

An IIFE (Immediately Invoked Function Expression) is a function that is defined and called at the same time. It creates a new function scope, isolating its internal variables from the global scope — a common pattern to avoid polluting global scope.

javascript

(function() {
    var privateVar = 'I am private';
    console.log(privateVar); // Output: I am private
})();

console.log(privateVar); // ReferenceError: privateVar is not defined

Module scope means that variables, functions, and classes declared in an ES6 module are scoped to that module by default. They are not added to the global scope and are not accessible from outside the module unless explicitly exported.

javascript

// module.js
const moduleVar = 'only in this module';
export function greet() {
    return 'Hello from module';
}
// moduleVar is NOT accessible outside this module unless exported

Global scope means a variable is accessible throughout the entire program. Local scope means a variable is only accessible within the specific function or block where it is declared. Local variables take precedence over global variables of the same name.

javascript

var message = 'global'; // global scope

function showMessage() {
    var message = 'local'; // local scope — shadows global
    console.log(message); // Output: local
}
showMessage();
console.log(message); // Output: global

With var, the loop variable is shared across all iterations because var is function-scoped. With let, each iteration creates a new binding in its own block scope, which is critical for callbacks and closures inside loops.

javascript

// Using var — all callbacks share the same 'i'
for (var i = 0; i < 3; i++) {
    setTimeout(() => console.log(i), 0); // Output: 3, 3, 3
}

// Using let — each iteration has its own 'i'
for (let j = 0; j < 3; j++) {
    setTimeout(() => console.log(j), 0); // Output: 0, 1, 2

Lexical scope (used by JavaScript) means a function's scope is determined by where it is defined in the source code. Dynamic scope (not used in JavaScript by default) would mean a function's scope is determined by where it is called from. JavaScript's this keyword exhibits dynamic-scope-like behaviour depending on the call site.

javascript

var x = 'global';

function foo() {
    console.log(x); // uses lexical scope — looks where foo was DEFINED
}

function bar() {
    var x = 'bar local';
    foo(); // Output: global — NOT 'bar local' (lexical, not dynamic)
}
bar();