Closures in Javascript
Closures are one of the most fundamental and powerful concepts in JavaScript. A closure gives you access to an outer function's scope from an inner function. This is essential for understanding how JavaScript works and is frequently asked in interviews.
Key Concepts
- Closures allow inner functions to access outer function variables
- Variables persist even after the outer function has returned
- Each closure has its own scope chain
- Commonly used for data privacy and module patterns
Basic Closure
outer() has finished executing, but inner() still has access to outerVariable.
Code
function outer() { let outerVariable = "I'm from outer function"; function inner() { console.log(outerVariable); // Can access outerVariable } return inner; // Return the inner function } const closure = outer(); closure(); // "I'm from outer function"
Closure with Parameters
Code
function createCounter() { let count = 0; // Private variable return function() { count++; // Access and modify the outer variable return count; }; } const counter1 = createCounter(); const counter2 = createCounter(); console.log(counter1()); // 1 console.log(counter1()); // 2 console.log(counter2()); // 1 (independent closure) console.log(counter1()); // 3
Closure in Loop (Common Interview Question)
Problem: All functions reference the same variable Solution 1: Use let (block scope) Solution 2: Use IIFE (Immediately Invoked Function Expression) Solution 3: Use bind.
Code
for (var i = 0; i < 3; i++) { setTimeout(function() { console.log(i); // Prints 3, 3, 3 (not 0, 1, 2) }, 100); } for (let i = 0; i < 3; i++) { setTimeout(function() { console.log(i); // Prints 0, 1, 2 }, 100); } for (var i = 0; i < 3; i++) { (function(j) { setTimeout(function() { console.log(j); // Prints 0, 1, 2 }, 100); })(i); } for (var i = 0; i < 3; i++) { setTimeout(function(j) { console.log(j); }.bind(null, i), 100); }
Module Pattern (Using Closures)
Code
const calculator = (function() { let result = 0; // Private variable return { add: function(x) { result += x; return this; }, subtract: function(x) { result -= x; return this; }, multiply: function(x) { result *= x; return this; }, getResult: function() { return result; }, reset: function() { result = 0; return this; } }; })(); calculator.add(10).subtract(3).multiply(2); console.log(calculator.getResult()); // 14
Closure with Higher-Order Functions
Code
function createMultiplier(multiplier) { return function(number) { return number * multiplier; }; } const double = createMultiplier(2); const triple = createMultiplier(3); console.log(double(5)); // 10 console.log(triple(5)); // 15
Data Privacy with Closures
log(account.
balance); // undefined (private) Common Interview Questions Q: What will be the output.
This will print 50 (from the closure in outer function) Q: Closure with this binding Arrow function doesn't have its own 'this' 'this' refers to global/window object, not person2.
Code
function createBankAccount(initialBalance) { let balance = initialBalance; // Private, cannot be accessed directly return { deposit: function(amount) { if (amount > 0) { balance += amount; return balance; } throw new Error("Amount must be positive"); }, withdraw: function(amount) { if (amount > 0 && amount <= balance) { balance -= amount; return balance; } throw new Error("Insufficient funds or invalid amount"); }, getBalance: function() { return balance; } }; } const account = createBankAccount(1000); console.log(account.getBalance()); // 1000 account.deposit(500); console.log(account.getBalance()); // 1500 function outer() { let a = 20; return function inner() { let a = 50; // This creates a new local variable, doesn't modify outer 'a' console.log(a); // 50 }; } const innerFn = outer(); innerFn(); // 50 function outer2() { let a = 60; outer()(); // Calls outer() which returns inner(), then immediately calls inner() } outer2(); const person = { name: "Kuldeep", age: 20, info: function() { console.log(`${this.name} is ${this.age} years old`); } }; person.name = "Ramesh"; person.info(); // "Ramesh is 20 years old" const person2 = { name: "Kuldeep", age: 20, info: () => { console.log(`${this.name} is ${this.age} years old`); } }; person2.info(); // "undefined is undefined years old"
Summary
Understanding closures is essential for mastering javascript. Practice these examples and experiment with variations to deepen your understanding.
Key Takeaways
- closures is a fundamental concept in javascript
- Practice with these examples to build confidence
- Experiment with variations to explore edge cases
- Understanding closures will help you in technical interviews