R
Rishtaara
JavaScript Fundamentals
Lesson 16 of 28Article18 min

Advanced Functions

A closure happens when an inner function remembers variables from the outer function, even after the outer function has finished.

Closures

A closure happens when an inner function remembers variables from the outer function, even after the outer function has finished.

This is useful for private data, counters, and factory functions.

Real-life example: A bank locker keeps your items safe inside. Only your key (inner function) can open it — outsiders cannot see what is inside.

Closure — private counter
function makeCounter(start = 0) {
  let count = start; // "private" — not visible outside
  return {
    add() { count++; return count; },
    get() { return count; },
  };
}

const score = makeCounter(10);
score.add(); // 11
score.add(); // 12
// score.count — undefined (protected)

Callbacks

A callback is a function you pass to another function. It runs later — after a click, a timer, or when data arrives.

Real-life example: You order food and give your phone number (callback). The restaurant calls you when the order is ready — you do not stand at the counter forever.

Callback after button click
function showMessage(message, callback) {
  console.log(message);
  callback();
}

document.querySelector("#btn").addEventListener("click", () => {
  showMessage("Lesson saved!", () => {
    alert("Great job on Rishtaara!");
  });
});

Rest and spread parameters

Rest (...args) collects extra arguments into an array. Spread (...arr) expands an array or object into separate items.

Real-life example: Rest is like putting loose coins into one pouch. Spread is like pouring that pouch back out onto the table one coin at a time.

Rest and spread
function sum(...numbers) {
  return numbers.reduce((total, n) => total + n, 0);
}
sum(2, 3, 5); // 10

const scores = [85, 92, 78];
const allScores = [70, ...scores, 95]; // [70, 85, 92, 78, 95]

const user = { name: "Asha", grade: 10 };
const updated = { ...user, grade: 11 }; // clone + change one field

IIFE (Immediately Invoked Function Expression)

An IIFE is a function that runs right away. It creates its own scope so variables do not leak into the global space.

Modern code uses modules instead, but you will still see IIFEs in older scripts.

Real-life example: A pop-up stall opens, sells snacks, and closes — all in one day. It does its job once and leaves no mess behind.

IIFE — run once, stay private
(function () {
  const secretKey = "abc123";
  console.log("App started with key:", secretKey);
})();

// secretKey is not available here — good for avoiding name clashes

Higher-order functions

A higher-order function takes another function as an argument, returns a function, or both. Array methods like map, filter, and reduce are higher-order functions.

Real-life example: A teacher (higher-order function) gives homework to students (functions). The teacher decides when and how each student works.

map, filter, reduce
const prices = [100, 250, 80];

const withTax = prices.map(p => p * 1.18);
const bigOnes = prices.filter(p => p >= 100);
const total = prices.reduce((sum, p) => sum + p, 0);

console.log(withTax);  // [118, 295, 94.4]
console.log(bigOnes);  // [100, 250]
console.log(total);    // 430

call, apply, and bind (brief)

These methods control what this points to inside a function. call and apply run the function right away; bind returns a new function with this fixed.

Real-life example: Borrowing a friend's bike (call/apply) means you ride it today with their name on the register. bind is like getting a spare key — same bike, same owner, ready anytime.

call, apply, bind
const person = {
  name: "Ravi",
  greet(greeting) {
    console.log(`${greeting}, ${this.name}`);
  },
};

const other = { name: "Sita" };

person.greet.call(other, "Hello");   // Hello, Sita
person.greet.apply(other, ["Hi"]);   // Hi, Sita

const greetSita = person.greet.bind(other);
greetSita("Namaste");                // Namaste, Sita