Here is an idea that quietly reshapes how you write code: a function can be a value. Just like a number or a string, you can store it in a variable, pass it into another function, or return it as a result. A function that takes a function as an argument, or returns one, is called a higher-order function.
Why care? Because a huge amount of everyday code is really "walk through a list and do something to each item." Higher-order functions let you write the walking once, for all time, and just hand in the doing. Three of them — map, filter, and reduce — cover an astonishing fraction of all list processing you'll ever do.
Let's make it concrete.
Same machine, two totally different results — because the function itself was the input. That flexibility is the whole game.
map takes a list and a function, and returns a new list
where each item has been run through the function. The list stays the same length; each element is
transformed. It replaces the classic "make an empty array, loop, push" ritual with one line.
Notice map is pure: it returns a fresh array and never disturbs the original.
filter takes a predicate — a function that returns
true or false — and returns a new list of just the items for which it
said true. The list can come out shorter; nothing gets transformed.
reduce is the powerful one. It walks the list carrying an
accumulator — a running result — and on each item combines the accumulator with
that item to make the next accumulator. When the list runs out, the accumulator is your answer.
You give it two things: the combining function (acc, x) => ... and a
starting value.
The starting value seeds the accumulator and, crucially, decides the answer for an
empty list: summing nothing should give
Because each returns a new list, you can chain them into a readable pipeline that reads like a sentence: take the numbers, keep the evens, square them, add them up.
Compare that to the equivalent tangle of a loop with an if, a temporary array, and an
accumulator. The higher-order version says what you want, not how to shuffle
indices — that's the declarative payoff.
The callbacks you pass to map/filter/reduce should be
pure. It's tempting to reach for map when you really mean "do a
side effect for each item" — but that's a misuse:
forEach (or a plain loop), not map, when you
only want a side effect and are ignoring the returned array. map that you don't
use just builds a throwaway list.reduce whose callback pushes into a shared array quietly reintroduces
all the bugs immutability was protecting you from.Rule of thumb: transforming data → map/filter/reduce; poking the outside world → forEach.