Closures in JavaScript

Inner function keeps the outer variables. That counter example is the whole point.

IntermediateFunction ProgramsExample 3 of 3
closures.js
1// Closure: Function has access to outer function's variables
2
3// Example 1: Basic closure
4function outerFunction(x) {
5 // Outer function's variable
6 let outerVar = x;
7
8 // Inner function (closure)
9 function innerFunction(y) {
10 console.log("Outer:", outerVar, "Inner:", y);
11 return outerVar + y;
12 }
13
14 return innerFunction;
15}
16
17let closure = outerFunction(10);
18console.log("Result:", closure(5));
19
20// Example 2: Counter using closure
21function createCounter() {
22 let count = 0;
23
24 return function() {
25 count++;
26 return count;
27 };
28}
29
30let counter1 = createCounter();
31let counter2 = createCounter();
32
33console.log("\nCounter 1:", counter1());
34console.log("Counter 1:", counter1());
35console.log("Counter 2:", counter2());
36console.log("Counter 1:", counter1());
37
38// Example 3: Private variables
39function createBankAccount(initialBalance) {
40 let balance = initialBalance; // Private variable
41
42 return {
43 deposit: function(amount) {
44 balance += amount;
45 return balance;
46 },
47 withdraw: function(amount) {
48 if (amount <= balance) {
49 balance -= amount;
50 return balance;
51 } else {
52 return "Insufficient funds";
53 }
54 },
55 getBalance: function() {
56 return balance;
57 }
58 };
59}
60
61let account = createBankAccount(100);
62console.log("\nInitial balance:", account.getBalance());
63console.log("After deposit 50:", account.deposit(50));
64console.log("After withdraw 30:", account.withdraw(30));
65console.log("Final balance:", account.getBalance());
66
67// Example 4: Function factory
68function createMultiplier(multiplier) {
69 return function(number) {
70 return number * multiplier;
71 };
72}
73
74let double = createMultiplier(2);
75let triple = createMultiplier(3);
76
77console.log("\nDouble 5:", double(5));
78console.log("Triple 5:", triple(5));
79
80// Example 5: Closure with loop (common mistake)
81console.log("\nClosure in loop:");
82for (var i = 0; i < 3; i++) {
83 setTimeout(function() {
84 console.log("var i:", i); // Prints 3, 3, 3
85 }, 100);
86}
87
88// Solution: Use let
89for (let j = 0; j < 3; j++) {
90 setTimeout(function() {
91 console.log("let j:", j); // Prints 0, 1, 2
92 }, 200);
93}

Output

Outer: 10 Inner: 5
Result: 15

Counter 1: 1
Counter 1: 2
Counter 2: 1
Counter 1: 3

Initial balance: 100
After deposit 50: 150
After withdraw 30: 120
Final balance: 120

Double 5: 10
Triple 5: 15

Closure in loop:
var i: 3
var i: 3
var i: 3
let j: 0
let j: 1
let j: 2

What's going on

A function returned from another function still sees the outer lets. The bag stays.

Loop plus var plus closure: all callbacks share one i. let fixes it. That interview question.