A function is also a value: you can pass it to another function. A callback is a function given to another operation to call when needed. Array methods use callbacks to describe what should happen to each item.
map returns a new array with one result per original item. filter returns a new array containing only items whose callback returns a truthy result. Neither method changes the original array’s membership, but they do not deep-copy objects. A filtered object is still the same object.
An arrow function is a compact way to write a function: minutes => minutes >= 20. Without braces, the expression is returned. With braces, you must write return yourself. Start with named function declarations if that is clearer; arrow syntax is a convenience, not an achievement.
Do not use map just to print things. Its purpose is to produce a new array. A for…of loop remains a good way to perform a sequence of actions. join(", ") turns an array into a readable string with a separator.
Start with a named callback
You can use an ordinary function declaration before learning the compact arrow spelling. keepLong below describes the rule for one item. filter calls it for each number and keeps the numbers for which it returns true. Pass keepLong, without parentheses: filter needs the function, not the result of calling it once yourself.
function keepLong(minutes) {
return minutes >= 20;
}
const selected = [10, 25, 40].filter(keepLong);
console.log(selected.join(", "));Check your prediction
25, 40For 10 the function returns false; for 25 and 40 it returns true. value => value >= 20 is a shorter function with the same one-item rule. The name value is a parameter you choose, not a special word.
Predict before running
Which items survive filtering? Does map change their count?
const minutes = [10, 25, 40];
const longSessions = minutes.filter(value => value >= 20);
const labels = longSessions.map(value => `${value} min`);
console.log(labels.join(", "));
console.log(minutes.length);Check your prediction
25 min, 40 min
3Trace each statement in order. If your prediction differed, describe the first place your mental model and the result diverged before trying again.
Arrow bodies can lose their return value
A compact arrow returns its expression automatically. A block body with braces requires return. Braces are useful when you need temporary variables or multiple steps, but forgetting return makes each call produce undefined.
The example keeps the bug runnable so you can inspect it. Fix the broken callback before using its result anywhere else. Then rewrite the working arrow as a named function declaration and pass that name to map without calling it yourself.
const minutes = [10, 20];
const broken = minutes.map(value => {
value * 2;
});
const working = minutes.map(value => {
return value * 2;
});
console.log(broken[0] === undefined);
console.log(working.join(", "));Check your prediction
true
20, 40The first block calculates and discards a value. return sends the calculated value back to map.
Read a transformation in stages
For “take completed sessions and print their topics”, filter determines which records survive, map changes each surviving record into text, and join combines the text. Check the length after each stage. A filter can reduce length; map preserves it. If your count changes after map, you are probably inspecting a different variable.
Map does not guarantee a side-effect-free callback. A callback that assigns to a record’s property still mutates that shared object. Prefer returning a new record with spread when you intend a revised copy. Use a for…of loop when your aim is to perform actions without building a result array.
Practice: convert durations into labels, then filter durations before converting them. Explain why filtering numeric values before formatting is easier than trying to recover numbers from the labels afterward.
Your turn
Callbacks, map() & filter(): practise
From the supplied records, select completed sessions, get their topic names, and print Loops, Arrays. Try no completed records: join should produce an empty string.
const sessions = [
{ topic: "Loops", done: true },
{ topic: "Objects", done: false },
{ topic: "Arrays", done: true }
];
// Filter, map, then join.Hint 1: the idea
Filter answers which records; map answers what to keep from each record.
Hint 2: a first step
Use session => session.done for filter and session => session.topic for map.
Show one solution
const sessions = [
{ topic: "Loops", done: true },
{ topic: "Objects", done: false },
{ topic: "Arrays", done: true }
];
const completed = sessions.filter(session => session.done);
const topics = completed.map(session => session.topic);
console.log(topics.join(", "));Loops, ArraysSeparate variables make the stages easy to inspect. Rewrite this with for…of as a review: the longer version is equally valid if it expresses the behavior clearly.
What you should be able to explain
- Compare an expression arrow with a block arrow.
- Which stage selects records and which transforms them?
- Why can a map callback still mutate input objects?
Completion is saved in this browser only. It does not measure mastery.