There comes a time in the learning path for most programmers when they discover a function called map. Up until discovering the map function, you might use a for loop whenever you needed your machine to perform some action many times. In the common case, that action would be transforming some data.

Imperative

For example, a salesperson on your team hands you a big list of email addresses. Not a great deal of care was taken in validating the email addresses as they were coming in, so some of them are uppercase, some of them are lowercase, and some of them are a mix of the two. The for loop approach to transforming the data looks like this:

This approach works, but it involved a painful amount of ceremony to achieve what is in reality a simple and common operation. Our function with the for loop encodes so much detail that we didn’t intend to express. A few sore points:

We told the machine that it needs to create a temporary list that it copies email addresses to.

We told the machine to first count how many email addresses we want to transform, and then move through the list of email addresses exactly that number of times.

We told the machine to create a counter so it knows what position of the email address list its operating on.

We told the machine which direction it should count in, which implies that ordering is important at this stage — which it isn’t.

This is the imperative approach to programming. We are dictating to the machine how it should do its job.

Confused

We want to clean up the previous approach, so we reach for the map function. As we read through any documentation for the map function, we see words like “array”, “each”, and “index”. This would suggest we could treat map as a slightly less ceremonious for loop, and indeed we can. Let’s change our original function.

This works, and is cleaner than the for loop approach. Aside from there being fewer characters in the code snippet, we’re not telling the machine how to keep track of indexes or which direction it should work through our list.

However, this is not enough. This is still the imperative approach to programming. We are still dictating far too much. We are concerning ourselves with details we need not concern ourselves with, and we are holding our computer’s hand every step of the way.

Declarative

What we need is to change the way we think about the data transformation. We don’t think “Computer, I need you to take the first element of this list, then lowercase it, then push it to this other list, then return the list”. Instead we think “Computer, I have a list of mixed-case email addresses, and I need a list of lower-case email addresses. Here’s the function that does lowercasing.

It’s not a stretch to argue that this is more readable to a human, and that’s what programming is all about: expressing ideas to other humans, be they other developers or your future self. The above snippet says “Our valid data is our mixed emails list mapped over the downcase function”.

Expressing ideas at such a high level like this is a core tenet of the school of functional programming, and that’s essentially what we’re doing. Complex programs are built by combining simple components which have a single responsibility and are easy to understand.

There are several further advantages to this approach. In no particular order:

Our lowercasing function provides the simplest-possible interface; a single value in, and a single value out.

There are fewer moving parts, so our logic is easier to understand, easier to test, and is less likely to break.

Our logic does just one thing, so it’s easy to reuse and combine with other functions in order to express more complex ideas.

It’s not uncommon for the size of a codebase to shrink dramatically when going down this declarative road.

Although the use of an anonymous function as the first argument to map() is common, I recommend pulling functions out and giving them meaningful names. This helps to document your intent with the function, so another developer later can understand what the method does by reading the name instead of having to
mentally parse the implementation.

Performance

In the vast majority of cases, the choice between the map function and a for loop will have no performance implications in real-world code. The for loop ismarginally faster, but the difference is not worth considering unless you’re writing some form of graphics or physics engine, and even then it doesn’t make sense to introduce this optimization before profiling your performance-critical code so you have some hard data to work on.

Wrapping Up

The functional approach of separating logic into simple pure methods and applying those methods to data structures will make your code more concise, more robust, and easier to understand. The concept is general, and more general concepts allow for greater code reuse. Learning to think this way will improve not only your JavaScript, but your work with most other programming languages too; you can apply this approach in Ruby as readily as you can in Haskell.

So, next time you reach for a for loop, reconsider. Bear in mind that the data structure you begin with doesn’t necessarily need to be a flat array; you can start with an object, pull out its values, then map a function over that and end by sorting the resulting array. You can even use a library such as Underscore to map over object preserving the keys.

Can you think of any more creative ways of using the map() function? Experiment, and watch your code shrink.

Jezen Thomas is a freelance software developer spending most of his time
writing software with Ruby and JavaScript. He shares his thoughts by
speaking at conferences and writing on his
blog.

Free Guide:

7 Habits of Successful CTOs

"What makes a great CTO?" Engineering skills? Business savvy? An innate tendency to channel a mythical creature (ahem, unicorn)? All of the above? Discover the top traits of the most successful CTOs in this free guide.

http://cashpath20.com JudyJMena

.❝my neighbor’s mother is making $98 HOURLY on the
internet❞….

A few days ago new McLaren F1 subsequent after earning 18,512$,,,this was my
previous month’s paycheck ,and-a little over, $17k Last month ..3-5 h/r of work a day ..with extra
open doors & weekly paychecks.. it’s realy the
easiest work I have ever Do.. I Joined This 7 months ago and now making over
$87, p/h.

Learn More right Here….website on my PrroFile
+fdsdfd

İsmail Şener

It’d be very helpful article. Thanks a lot, it gave me a 1 level in this environment :p

ShadowCodex

This was a really good article, and a lot of people need to read this to up their game a little.

Adam Reineke

If you don’t need the return values from your callback function, skip .map and use .forEach, which has similar support but should drop the overhead of building an array the callback return values.

Olu O

Just came here to say that. The .map higher order function makes sense in the last case as you’re returning a new array, but in the first two examples, at least the way the code is written, a .forEach function is really what you should be using if you’re pushing values to the ‘lowerCaseEmails’ array.

The point is to make that function shorter, but not as short as the last example:
['email1', 'email2' ,'email3'].map(toLowerCase);

http://jezenthomas.com/ Jezen Thomas

In your first snippet, you have created two anonymous functions that do the same thing, which is repetitive.

In your second snippet, you have coupled your function with the context of emails. What happens if you want the same logic within a different context? What if you were lowercasing URLs?

The `map` function is a general concept, and this generalisation allows you to stop repeating yourself.

> The point is to make that function shorter, but not as short as the last example

What’s wrong with the last example being so short?

Edwin Reynoso

The first snippet I repeated myself on purpose, showing the point of the function. All I’m trying to say is that in your second function you could make it shorter, and even shorter in your last

http://jezenthomas.com/ Jezen Thomas

Your third snippet doesn’t work in JavaScript. It works in Ruby and a bunch of other languages though.

In Ruby:

['FOO', 'BaR', 'baz'].map(&:downcase)

Edwin Reynoso

The third snippet is representing what was done at the end of this article, for some reason I can’t open the article but still can reply from disqus. I wasn’t trying to pass in the method to call and map

Nathan Strutz

It’s a bit more complex with Javascript. toLowerCase is a String member function, so you have to tell map to “call” the toLowerCase function:

Why not? Because the Confused section is *deliberately* failing to use .map() properly. It’s an example of what somebody might do if they don’t properly understand how to use it. (Though I disagree with the author that doing this is “cleaner” than a for loop. Using .map() properly is cleaner, but this is messier.)

Bob Jones

Handy. It’s also important to realize that you can’t “break” from .map() or .forEach(). Lodash does have some functions that allow you to “break”. But generally, you’ve committed to the whole array with these.

Rafael Bitencourt

“…you’ve committed to the whole array with these”. Don’t forget you can always run .filter or anything like that before .map

Bob Jones

Also to be aware, with generators coming/here, there may be cases where you can’t yield from a generator inside a plain-ol’-function, including a .map callback.

H.D. Broreau

The usage of map in the “Confused” code example is highly confusing. I don’t know if this is done on purpose but since it is not mentioned at all in the surrounding text I assume it is not.

Using map and not consuming its return value should not happen and will trick a lot of beginners reading this article into using map for its side effects, which is -100% functional programming and probably the exact opposite of what the author is trying to achieve. Please change it to forEach and have people learn things in the right way, even if they are beginners.

Kevin

I completely agree: the code in the “Confused” section is unarguably worse than either the imperative or functional approaches.

Kevin

I completely agree: the code in the “Confused” section is unarguably worse than either the imperative or functional approaches.

http://www.earwicker.com Daniel Earwicker

Absolutely, and I’d also add that ES2015 has added a new form of imperative for-loop that improves on forEach, and works on any iterator (arrays, generators or user-defined).

This is a strong indication that in a mainstream language like JS, imperative loops sometimes are the only sensible option, hence this latest acknowledgement in new language support.

Andrew Ritter

The return value of map() is a new array — Isn’t he consuming it in the ‘confusing’ example via the closure within the getEmailsInLowercase function?

http://jezenthomas.com/ Jezen Thomas

It was intentional. I would have thought the section being called ‘Confused’ gave it away. It is something I have seen confused developers do, incorrectly. The narrative of the article is to not shoehorn a functional concept into imperative programming. It is to adopt declarative thinking instead. Changing it to `forEach` would be to suggest developers continue thinking imperatively.

Jens Melgaard

Perhaps the “Confused” step should just have been skipped all together. Map is fairly easy to understand anyways… Using [].forEach wouldn’t be “imperative” as much as it would just be the incorrect use of it here…

Using forEach where appropriate would IMO be just as declarative. It’s perhaps just more uncommon that you just wan’t to perform something for each item and not return a result, that doesn’t rule it out though.

I think Streams/Irritable/Generators/Enumerable or whatever the languages call them these days (and especially async handling where supported), would have a nice story in here, this is where it becomes absolute obvious that we should change the way we think about performing operations on sequences.

What I’m thinking is, since in this case particular example, the logic we want to apply to each email address is simple, it’s just to make it lower-case, it’s not necessary to use a function for it.
But if the logic is more complicated, then a function might still recommended for clarity and reusability.

Scott Ashmore

This is the approach I would take but using the function keyword instead. Is it not considered bad to use an arrow function when it’s not necessary?

quazecoatl

Huh, why is the ES6 arrow function a “mistake”? It’s a great new JavaScript feature, it’s not a mistake :)

Scott Ashmore

I didn’t say it was a mistake, I simply asked if it was bad to use it.

quazecoatl

It’s not bad at all to use it, next versions of Javascript, ES6 and ES7 have awesome features.
Go check it out!

Baz

It’s the opposite, you should always use the arrow function except when you can’t, ie need a new scope. This is because the arrow function is simpler with less possibilities and therefore easier to reason about.

Scott Ashmore

Ah ok, thanks Baz!

Bogdan Pascanu

Or even simpler, you can do this in two lines of code. No need to declare extra functions in this case.