Skip to content

Beginner · Functions and closures · topic 14 of 61 · 30 min

Scope and closures

Explanation

Scope decides where a variable can be seen; JavaScript uses lexical scope, so it depends on where the code is written. A closure is a function together with the variables from its surroundings that it remembers, even after the outer function has finished. Closures give you private state, counters and function factories.

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.

javascript
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 defined

Lexical 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.

javascript
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)
Think of it like this: A closure is like a tiffin box packed at home. The function (the person) leaves the house (the outer function returns), but carries the tiffin (the variables) and can still open it hours later at the office. Each person gets their own tiffin.

Function factories

A factory is a function that makes other functions, each set up with its own remembered values.

javascript
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)); // 950

Private state

Closures let you hide data so that it can only be changed through the functions you choose. This protects it from accidental changes.

javascript
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 directly

The classic var-in-a-loop bug

javascript
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);
}
Prints var: 4 three times, then let: 1, let: 2, let: 3.

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.

Careful: Closures keep their variables alive. If a closure remembers a huge array and the closure lives for the whole app (for example in a long-lived event handler), that memory is never freed. Only capture what you need.
Tip: Interview favourite: "What is a closure?" Answer: a function that remembers the variables from the scope where it was created, even after that scope has finished. Then show makeCounter.

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

Scope and closures

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.

javascript
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'));
Prints OTP sent three times, then Limit reached, try later.

Practice (0/3 done)

Task 1 · Code · Javascript

Write makeCounter() that returns a function. Each call of that function returns the next number: 1, 2, 3… Two counters must count separately.

Task 2 · Code · Javascript

Write makeMultiplier(factor) that returns a function multiplying its input by factor. makeMultiplier(3)(5) is 15.

Task 3 · Code · Javascript

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

Question 1

1.What is a closure?

Question 2

2.for (var i = 0; i < 3; i++) setTimeout(() => console.log(i)); What is printed?

Question 3

3.const add5 = ((n) => (x) => x + n)(5); What is add5(10)?

Question 4

4.What does "lexical scope" mean?

Read more (free)

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.

From Scope, hoisting and closures

A function calls its closure parameter many times, and the closure may change its captured state. Which bound fits?Related

Answer: FnMut

FnMut allows repeated calls that mutate state.

From Closures

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.

From Variadic functions, function values and closures

const a = [1, 2, 3]; a[10] = 4; console.log(a.length) prints…Related

Answer: 11

Setting index 10 makes the length 11 (with empty slots).

From Predict-the-output questions

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. 1 more topic in “Functions and closures” before its exam: Higher-order functions and recursion.
  2. Module 3 exam: Functions and closures · 12 questions · 25 min, without help. 5 topics of this module still to finish first.
  3. Then the next module, Arrays and objects. 61 topics left in the course before the final exam.

← Previous: Parameters: defaults, rest and options objects