Scope and closures
Scope
Scope decides where a variable can be used.
- Variables declared with
letandconstare block-scoped: they exist only inside the{ }where they're declared. - Variables declared inside a function are visible only inside that function.
- Variables declared outside everything are global.
JavaScript
const appName = "CodeMIRAI"; // global
function show() {
const message = "inside show"; // function scope
if (true) {
const inner = "inside the if"; // block scope
console.log(appName, message, inner);
}
console.log(typeof inner); // "undefined": inner doesn't exist here
}
show();
console.log(typeof message);Inner scopes can see outer variables; outer scopes can't see inner ones.
Closures
A closure is a function that remembers the variables from the place it was created, even after that place has finished running.
JavaScript
function makeCounter() {
let count = 0; // private to this counter
return function () {
count++;
return count;
};
}
const counterA = makeCounter();
const counterB = makeCounter();
console.log(counterA(), counterA(), counterA());
console.log(counterB());makeCounter has finished, yet the returned function still reaches count. Each call to makeCounter creates a separate count, so the two counters don't interfere.
Private state
Closures give you data that nothing outside can touch:
JavaScript
function createWallet(start) {
let balance = start;
return {
deposit(amount) { balance += amount; },
spend(amount) {
if (amount > balance) return "Not enough money";
balance -= amount;
return "OK";
},
get balance() { return balance; },
};
}
const w = createWallet(100);
w.deposit(50);
console.log(w.spend(500), w.spend(30), w.balance);
console.log(w.balanceValue); // there's no way to reach the variable directlyFunction factories
JavaScript
const multiplier = (factor) => (n) => n * factor;
const double = multiplier(2);
const triple = multiplier(3);
console.log(double(10), triple(10));The classic loop gotcha
With let, each loop iteration gets its own variable, so closures capture the right value:
JavaScript
const fns = [];
for (let i = 0; i < 3; i++) {
fns.push(() => i);
}
console.log(fns.map(f => f())); // [0, 1, 2]With the old var, all three would share one variable and print [3, 3, 3], which is one more reason modern code uses let.
Finished this lesson?Mark it complete to earn +20 XP and move your progress on.