Beginner · Functions and closures · topic 14 of 61 · 30 min
Scope and closures
Explanation
Scope: where a name is visible
Scope is the region of code where a variable exists. A variable made inside a function is local to it. A variable made with let or const inside { } exists only in that block. Code can look OUTWARD to see variables in surrounding scopes, but never inward.
const shop = 'Gupta Stores'; // outer (module) scope
function printBill() {
const total = 450; // local to printBill
console.log(shop, total); // can see shop (outer) and total
}
printBill();
// console.log(total); // ReferenceError: total is not definedLexical scope
Lexical means "decided by where the code is written". A function can use variables from the place where it was DEFINED, not from where it is called. This is the key to closures.
Closures
When an inner function uses a variable from an outer function, it keeps a live link to that variable. Even after the outer function returns, the inner function still remembers it. The function plus the remembered variables is called a closure.
function makeCounter() {
let count = 0; // private: nothing outside can touch it
return function () {
count++;
return count;
};
}
const nextToken = makeCounter();
console.log(nextToken()); // 1
console.log(nextToken()); // 2
const otherQueue = makeCounter();
console.log(otherQueue()); // 1 (its own separate count)Function factories
A factory is a function that makes other functions, each set up with its own remembered values.
function makeDiscount(percent) {
return (price) => price - price * percent / 100;
}
const diwaliSale = makeDiscount(20);
const memberPrice = makeDiscount(5);
console.log(diwaliSale(1000)); // 800
console.log(memberPrice(1000)); // 950Private state
Closures let you hide data so that it can only be changed through the functions you choose. This protects it from accidental changes.
function createWallet(start) {
let balance = start;
return {
pay(amount) {
if (amount > balance) return false;
balance -= amount;
return true;
},
getBalance: () => balance,
};
}
const wallet = createWallet(500);
wallet.pay(120);
console.log(wallet.getBalance()); // 380
console.log(wallet.balance); // undefined: there is no way to set it directlyThe classic var-in-a-loop bug
for (var i = 1; i <= 3; i++) {
setTimeout(() => console.log('var:', i), 0);
}
for (let j = 1; j <= 3; j++) {
setTimeout(() => console.log('let:', j), 0);
}var makes ONE i for the whole loop; by the time the timers run, the loop has finished and i is 4. let makes a NEW j for every round, so each callback closes over its own value.
Need help?
Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.
Try:
Watch the lesson
Scope and closures · 1/7
In this lesson you will learn about scope and closures, one of the most important ideas in JavaScript.
Prefer a video by a teacher? Find free videos on “javascript closures explained lexical scope” on YouTube ↗
In real life: A rate limiter for an OTP button
A login page must not let users request more than three OTPs. A closure keeps the attempt count private inside the limiter, so no other code can reset it by mistake.
function limitCalls(fn, max) {
let calls = 0;
return (...args) => {
if (calls >= max) return 'Limit reached, try later';
calls++;
return fn(...args);
};
}
const sendOtp = limitCalls((phone) => `OTP sent to ${phone}`, 3);
for (let i = 0; i < 4; i++) console.log(sendOtp('98xxxxxx10'));Practice (0/3 done)
Write makeCounter() that returns a function. Each call of that function returns the next number: 1, 2, 3… Two counters must count separately.
Write makeMultiplier(factor) that returns a function multiplying its input by factor. makeMultiplier(3)(5) is 15.
Write once(fn): it returns a new function that calls fn only the FIRST time and returns that result; later calls return the first result again without calling fn. (Useful for "initialise the payment SDK only once".)
Quick quiz
Read more (free)
Related help
Before this, learn
This topic builds on these. If something here feels new, open them first.
Related topics
- Higher-order functions and recursionFunctions and closures · same module
- Arrow functionsFunctions and closures · same module
- Scope, hoisting and closuresFrontend Web Development · JavaScript in depth
- ClosuresRust Programming · Closures, iterators and smart pointers
- Variadic functions, function values and closuresGo Programming (backend and cloud) · Control flow and functions
- Predict-the-output questionsInterview preparation and career
Questions people ask about this
Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.
What is a closure?
Answer: A function plus the variables from where it was created that it remembers
Closures keep access to the variables of the scope where the function was defined.
for (var i = 0; i < 3; i++) setTimeout(() => console.log(i)); What is printed?
Answer: 3 3 3
var gives one shared i, which is 3 when the timers run.
const add5 = ((n) => (x) => x + n)(5); What is add5(10)?
Answer: 15
The outer arrow is called with 5; the returned inner function remembers n = 5.
What does "lexical scope" mean?
Answer: Scope decided by where code is written
Lexical scope depends on the position of the code in the source.
What is a closure?Related
Answer: A function together with the outer variables it remembers
A closure is a function plus the variables from where it was created, which stay alive as long as the function does.
A function calls its closure parameter many times, and the closure may change its captured state. Which bound fits?Related
What is a closure?Related
Answer: A function value that remembers variables from where it was created
A closure captures and keeps alive the outer variables it uses.
const a = [1, 2, 3]; a[10] = 4; console.log(a.length) prints…Related
Pass the quiz (60% or more) or mark this topic as done when you are ready.
Your progress is saved on this device only.
Next steps
- 1 more topic in “Functions and closures” before its exam: Higher-order functions and recursion.
- Module 3 exam: Functions and closures · 12 questions · 25 min, without help. 5 topics of this module still to finish first.
- Then the next module, Arrays and objects. 61 topics left in the course before the final exam.