map and filter
In the previous lesson the worker at the conveyor only stamped the boxes, and the finished goods went nowhere. Yet one array often has to become another: prices with a discount, or only the positive numbers.
With forEach a new array would have to be built by hand with push, since the method itself returns undefined. Picture a second belt next to the conveyor. The worker takes a box from the first belt and puts what comes out onto the second one. This is how the map method works: it builds the new array itself.
const prices = [10, 25, 40];
const doubled = prices.map((p) => p * 2);
console.log(doubled); // [ 20, 50, 80 ]
console.log(prices); // [ 10, 25, 40 ]Let's go through the example line by line:
pricesis an array of three prices.prices.map((p) => p * 2)calls the callback for each price and collects the callback's answers into the new arraydoubled.- The first
console.logcall prints[ 20, 50, 80 ]. - The second prints
[ 10, 25, 40 ]: the original array stayed as it was.
map transforms each element
map calls the callback for each element and puts the callback's results into a new array. The new array has as many elements as the original: one result for each element. map does not change the original array itself, so prices stays as it was.
Here the belt analogy limps. In a real factory a box leaves the first belt, while the array prices stays whole after map, with every element in its place.
map fits when each element needs exactly one result: a price gets a discount, a name gets capital letters. The callback gets the element and its index, as in forEach.
The callback can return a value of any type. The call ["ann", "bob"].map((name) => name.toUpperCase()) gives the array of strings ["ANN", "BOB"].
Interviewers often ask how map differs from forEach. The answer is short: map returns a new array of the callback's results, while forEach always returns undefined.
filter keeps a part
Now an inspector stands by the belt. The inspector looks at each box and decides whether to let it through to the second belt or take it off. This is how filter works.
filter also calls the callback for each element, but the callback's result serves as a condition. The new array gets the elements themselves for which the callback returned a truthy value. The rest are dropped, so the new array can be shorter than the original, or empty.
The callback need not return exactly true or false: its result is checked like the condition of an if.
const nums = [4, 7, 10, 3];
console.log(nums.filter((n) => n > 5)); // [ 7, 10 ]
console.log(nums.filter((n) => n > 100)); // []Let's go through both calls:
- the condition
n > 5holds for7and10, andfilterreturns[ 7, 10 ]; - the condition
n > 100holds for no number, and the result is the empty array[].
filter does not change the original array either: nums still holds four numbers.
Chaining calls
map and filter return an array, so the next method can be called on the result right away. This form is called method chaining. The methods run from left to right, and each works on the array the previous one returned:
const scores = [55, 90, 72, 40];
const raised = scores.filter((s) => s >= 60).map((s) => s + 5);
console.log(raised.join(" ")); // 95 77A chain is like two stations on one conveyor. Let's pass them in order:
filterlets through only the scores from60up, which gives[90, 72].mapadds5to these two numbers only and returns[95, 77].join(" ")glues them into the string95 77.
The order of the stations matters. If the methods swap places, filter checks the numbers that were already raised.
Common mistake
The goal is to keep the even numbers, but the condition holds only the remainder:
const nums = [1, 2, 3, 4];
const evens = nums.filter((n) => n % 2); // ✗
console.log(evens);There is no error, but the program prints [ 1, 3 ]. An even number has the remainder 0, a falsy value, and filter drops such an element. An odd number has the remainder 1, a truthy value, and the element stays. Compare the remainder with zero: nums.filter((n) => n % 2 === 0) gives [ 2, 4 ].
Key points
mapreturns a new array of the same length made of the callback's results.filterreturns a new array of the elements for which the callback returned a truthy value.- Neither method changes the original array, and both return a new one, so their calls are chained.
- Unlike
map,forEachalways returnsundefined.
Subscribe to take the course
The course is free. Sign in with Telegram and subscribe to the channel to open every lesson.