Functions & Closures
Function samjho to JavaScript ka 70% samajh gaye — baaki closure ka jaadu hai.
JavaScript mein function banane ke 3 main tareeqe hain, aur har ek ka behaviour alag hai:
// 1. FUNCTION DECLARATION — fully hoisted ✅
console.log(greet("Sai")); // "Hello Sai" — works BEFORE definition!
function greet(name) {
return "Hello " + name;
}
// 2. FUNCTION EXPRESSION — assigned to variable
// console.log(add(2, 3)); // ❌ ReferenceError! (TDZ with let/const)
const add = function(a, b) {
return a + b;
};
// 3. ARROW FUNCTION — shortest syntax
const multiply = (a, b) => a * b;
const double = x => x * 2;
const shout = () => "HYDERABAD!";
Named vs Anonymous expressions:
// Anonymous (most common)
const add = function(a, b) { return a + b; };
// Named — useful for recursion & stack traces
const factorial = function fact(n) {
return n <= 1 ? 1 : n * fact(n - 1);
};
console.log(factorial(5)); // 120
// Note: "fact" is only available INSIDE the function
this or arguments (covered in Section 5).Functions ke parameters mein bahut flexibility hai JavaScript mein:
// DEFAULT PARAMETERS
function greet(name = "Bhai") {
return "Hello " + name;
}
console.log(greet()); // "Hello Bhai"
console.log(greet("Sai")); // "Hello Sai"
// REST PARAMETERS — collects all args into array
function sum(...nums) {
return nums.reduce((a, b) => a + b, 0);
}
console.log(sum(1, 2, 3, 4)); // 10
// Mix regular + rest
function log(level, ...messages) {
console.log(`[${level}]`, messages.join(" "));
}
...args gives a real Array (map, filter, reduce work). The arguments object is array-like but NOT a real Array — and it only exists in regular functions, NOT arrow functions.// arguments object — ONLY in regular functions
function showArgs() {
console.log(arguments); // { 0: 'a', 1: 'b', length: 2 }
console.log(arguments[0]); // 'a'
}
const arrowArgs = () => {
console.log(arguments); // ❌ ReferenceError in strict mode
// Or points to OUTER function's arguments in sloppy mode
};
// DESTRUCTURED PARAMETERS
function user({ name, city = "Hyderabad" }) {
return `${name} from ${city}`;
}
console.log(user({ name: "Sai" })); // "Sai from Hyderabad"
console.log(user({ name: "Ravi", city: "Mumbai" })); // "Ravi from Mumbai"
function f(arr = []) {} creates a NEW empty array each call — no shared reference bug unlike Python's mutable default args.Return aur scope samajhna functions ka sabse important part hai:
// IMPLICIT undefined — function without return
function noReturn() {
const x = 5;
// no return statement
}
console.log(noReturn()); // undefined
// EARLY RETURN pattern — clean & readable
function findUser(users, id) {
for (const user of users) {
if (user.id === id) return user; // exit early
}
return null; // not found
}
// No deep nesting needed!
Function Scope vs Block Scope:
function scopeDemo() {
// var is FUNCTION-SCOPED — leaks out of blocks!
var x = 1;
if (true) {
var x = 2; // SAME x — reassigns, not new variable
}
console.log(x); // 2
// let is BLOCK-SCOPED — stays inside {}
let y = 1;
if (true) {
let y = 2; // DIFFERENT y — only exists in this if block
}
console.log(y); // 1
// for loop — var leaks, let doesn't
for (var i = 0; i < 3; i++) {}
console.log(i); // 3 — var i leaked out!
for (let j = 0; j < 3; j++) {}
// console.log(j); // ❌ ReferenceError — let j stayed in loop
}
Yeh JavaScript ka sabse powerful concept hai. Dhyan se samjho — baaki sab closures pe based hai.
function createCounter() {
let count = 0; // ← This variable is "closed over"
return function inner() {
count++;
return count;
};
}
const counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3
// count survives even though createCounter() finished long ago!
inner is created, it "remembers" the variables in its outer scope (count). Even after createCounter() returns and its execution context is popped off the stack, the inner function still has a reference to count. The garbage collector cannot free count because something is still using it.// Each call creates a NEW closure with its own count
const counter1 = createCounter();
const counter2 = createCounter();
console.log(counter1()); // 1
console.log(counter1()); // 2
console.log(counter2()); // 1 — independent!
console.log(counter1()); // 3 — continues from 2
count. This is how JavaScript achieved encapsulation before classes with #private fields existed.function createBankAccount(initial) {
let balance = initial; // private — no direct access
return {
deposit(amount) { balance += amount; },
withdraw(amount) { if (amount <= balance) balance -= amount; },
getBalance() { return balance; },
};
}
const acc = createBankAccount(1000);
acc.deposit(500);
acc.withdraw(200);
console.log(acc.getBalance()); // 1300
// console.log(acc.balance); // undefined — truly private!Closures real-world mein har jagah use hote hain. Yeh patterns zyaada tar projects mein milte hain:
1. Module Pattern — private state ke saath:
const Calculator = (function() {
let history = []; // private
return {
add(a, b) {
const result = a + b;
history.push(result);
return result;
},
getHistory() { return [...history]; }, // return copy
};
})();
Calculator.add(2, 3);
Calculator.add(10, 20);
console.log(Calculator.getHistory()); // [5, 30]
// console.log(Calculator.history); // undefined — private!
2. Currying — functions ko chain karo:
function multiply(a) {
return function(b) {
return a * b;
};
}
const double = multiply(2);
const triple = multiply(3);
console.log(double(5)); // 10
console.log(triple(5)); // 15
// "a" is remembered via closure!
3. Event handlers — data remember karna:
function setupButton(label) {
const btn = document.createElement("button");
btn.textContent = label;
btn.addEventListener("click", function() {
console.log("Clicked:", label); // "label" remembered!
});
return btn;
}
// Each button's handler has its own closure with its own label
• Regular function:
this = jo call karta hai (dynamic binding)• Arrow function:
this = jahan function likha gaya hai (lexical binding)• Object methods mein arrow mat use karo —
this galat hoga!• Callbacks mein arrow use karo — outer
this mil jayega!const user = {
name: "Sai",
// ❌ Arrow — `this` is lexical (window/undefined in strict)
greetWrong: () => console.log(this.name),
// ✅ Regular — `this` is the object
greetRight() { console.log(this.name); },
};
user.greetWrong(); // undefined
user.greetRight(); // "Sai"Lo kar liya — Key Points:
- ✅ Function declarations are fully hoisted — expressions hit TDZ with let/const
- ✅ Arrow functions have no own
this, noargumentsobject - ✅
varis function-scoped,letis block-scoped — this matters in loops! - ✅ Closure = function + its lexical environment — inner function remembers outer variables
- ✅ Each function call creates a NEW closure — independent copies of closed-over variables
- ✅ Use closures for private data, currying, and module pattern
- ✅ Arrow for callbacks, regular for object methods —
thisrule
Want to track your progress?
Log in to save your place and pick up where you left off.
Progress track karna chahte ho?
Login karo apni progress save karne ke liye aur jahan chhoda tha wahan se shuru karo.
Login