Introduction
Think of an array as items moving on a factory belt. A callback function is a machine placed on that belt: every item passes through it once, and the machine does one small job to each item. The three machines in this lesson are map, filter and reduce — together they handle most of the array work in real apps, and they are the heart of the React series later. (Roman Urdu: map badalta hai, filter chhanta hai, reduce sab ko aik value mein samet deta hai.)
Key points
- The callback is the machine: you pass a small function into the method, and the method calls it once for every item, in order. You never call it yourself.
maptransforms: it runs the callback on every item and collects the results into a new array of the same length.mapnever edits the original — it builds new.(Roman Urdu: map har cheez ko badal kar aik nayi list banata hai, purani list waisi ki waisi rehti hai.)filterselects: it is a net. The callback returnstrueorfalsefor each item —trueitems stay in the new array,falseitems fall out. The new array can be shorter than the original.reducefolds into one value: a snowball. It carries an accumulator that starts at your start value, and each item folds into it, until one single value is left at the end.- Always give
reducea start value:reduce((sum, price) => sum + price, 0)— the0at the end is the start. Forget it and the first item becomes the start, which breaks empty arrays and can let strings sneak into a total. - Chain them: the result of
filteris an array, somapcan run on it, andreducecan finish the job — one clean line of steps. - Loops vs methods: a
forloop can do all of this, but a loop says how (step by step), while methods say what (transform, select, total) — shorter and clearer to read.(Roman Urdu: Loop tareeqa batata hai, methods matlab batate hain — is liye methods zyada saaf lagte hain.)
Code examples
Example 1 — map doubles every price
const prices = [250, 200, 300];
const doubled = prices.map((price) => price * 2);
console.log(doubled.join(", "));
console.log(prices.join(", "));What it does: The callback price => price * 2 is the machine on the belt: 250 goes in, 500 comes out; 200 becomes 400; 300 becomes 600. map collects those three results into a new array called doubled — prices itself is never touched.
What you will see: the console prints 500, 400, 600 first, then 250, 200, 300 — proof that the original array is exactly as it was.
Example 2 — filter keeps only what passes
const products = [
{ name: "Chai", price: 250, stock: 5 },
{ name: "Coffee", price: 200, stock: 0 },
{ name: "Cake", price: 300, stock: 3 },
];
const inStock = products.filter((product) => product.stock > 0);
console.log(inStock.map((product) => product.name).join(", "));
const above220 = products.filter((product) => product.price > 220);
console.log(above220.map((product) => product.name).join(", "));What it does: The first filter keeps only products whose stock is more than 0 — Coffee returns false and falls out of the net. The second filter uses a different test: only prices above 220 stay. The small map after each filter just picks out the names so we can print them.
What you will see: the console prints Chai, Cake first (Coffee is sold out), then Chai, Cake again (Coffee at 200 is also below 220).
Example 3 — reduce, then all three in a real app shape
const prices = [250, 200, 300];
const total = prices.reduce((sum, price) => sum + price, 0);
console.log(total);
const products = [
{ name: "Chai", price: 250, stock: 5 },
{ name: "Coffee", price: 200, stock: 0 },
{ name: "Cake", price: 300, stock: 3 },
];
const cards = products
.filter((product) => product.stock > 0)
.map((product) => product.name + " - Rs " + product.price);
console.log(cards.join(" | "));
const bill = products
.filter((product) => product.stock > 0)
.reduce((sum, product) => sum + product.price, 0);
console.log("TOTAL: Rs " + bill);What it does: Follow the snowball in the first reduce: the accumulator starts at 0, then folds in each price — 0, then 250, then 450, then 750. The app shape below it is how real screens are built: filter hides the sold-out Coffee, map turns each product that is left into card text, and a second chain uses filter plus reduce to print the bill total.
What you will see: the console prints 750, then Chai - Rs 250 | Cake - Rs 300, then TOTAL: Rs 550 — Coffee appears nowhere, because the filter removed it before the other machines ran.
Quick recap
map= transform every item into a new array; the original never changes.filter= keep only the items whose callback returnstrue.reduce= fold everything into one value — and always give it a start value.
Common mistakes
- Forgetting the start value in reduce — without the
, 0at the end, the first item becomes the accumulator, so an empty array throws an error and a list of strings can join into your "total" by accident. The fix: always write the start value, even when it is0or"". - Expecting map or filter to change the original array — they never edit; they return a new array. If you call
prices.map(...)and throw the result away, nothing happened. The fix: save the result in a variable and use that. - Forgetting to return in a block-body callback —
(price) => { price * 2; }returnsundefinedfor every item, so your new array is full ofundefined. The fix: either use the one-line form(price) => price * 2, or write the wordreturninside the braces.
Practice
- Start with
const marks = [45, 80, 62, 90, 30]. Usefilterto keep only the passing marks (50 and above), usemapto add 5 bonus marks to each of them, and print both new arrays. Check thatmarksitself did not change. - Make an array of four products with
name,priceandstock. Use one chain to print the names of only the in-stock products, and usereduceto print the total price of the in-stock products only.