DEV Community

Cover image for Stop using Array.map() everywhere πŸ₯΅
Suprabha
Suprabha

Posted on

Stop using Array.map() everywhere πŸ₯΅

Most of the time I used to see the snippet like this πŸ‘‡

const fruits = ["apple", "orange", "cherry"];
let text = "";
document.getElementById("main").innerHTML = text;
fruits.map(i => text += i );
Enter fullscreen mode Exit fullscreen mode

In the above snippet, we are adding fruits text to the DOM in main ID.
It seems there is no issue in the above snippet, Though there is one major issue, which we will be going see today.

Let's understand the issue by definition of map, map() method creates a new array populated with the results of calling a provided function on every element in the calling array.

example:

let n = [1, 2, 3, 4];
let add = n.map(i => i + 2);
console.log(add); // [3, 4, 5, 6]
Enter fullscreen mode Exit fullscreen mode

NOTE: Using map() method means returning a new collection of an array.

As discussed, map() method always returns a new array, so if you don’t have any use of a new array then never use map() method.
When you just need to iterate through an array, I will always recommend using other array methods like forEach or for..of.

example:

const fruits = ["apple", "orange", "cherry"];
let text = "";
fruits.forEach(myFunction);

document.getElementById("main").innerHTML = text;

function myFunction(item, index) {
  text += index + ": " + item + "<br>"; 
}
Enter fullscreen mode Exit fullscreen mode

Why do we care about it? πŸ™„

As we know, map() method always returns an array. If you just need to update DOM then storing those elements into memory form doesn't add any point.
Of course, for a small chunk of numbers nothing is going to happen, however, if we take a larger number here then it affects the performance side as it will store the value in memory which will be redundant.

Summary β…€

Stop using map() method, if you just need to iterate through an array.
Start using forEach or for...of method, if you want to iterate through an array.

Thanks for reading the article ❀️
Hope this post will be useful!

Buy Me A Coffee

🌟 Twitter πŸ“š Ebooks 🌟 Instagram

Oldest comments (30)

Collapse
 
suhakim profile image
sadiul hakim

Yeah,we should not use map method everywhere. There are many array methods available in Javascript like filter,find,foreach,reduce etc. We should use them then need.

Collapse
 
jonrandy profile image
Jon Randy πŸŽ–οΈ

In your first example, you are adding an empty string to the DOM

Collapse
 
aminnairi profile image
Amin • Edited

Hi @suprabhasupi and thanks for your article.

I wanted to point out that you could also have used map in a different way and still have the expected result.

const root = document.getElementById("root");

if (!root) {
  throw new Error("Root not found");
}

const fruits = ["banana", "apple", "pear"];

const indexed = fruits.map((fruit, index) => {
  return `#${index + 1}: ${fruit}`;
});

const html = indexed.join("<br>");

root.innerHTML = html;
Enter fullscreen mode Exit fullscreen mode

Although I agree with you, I would change the title from Stop using Array.prototype.map everywhere to Start learning when to use Array.prototype.map.

A do/don't kind of article would have been great for beginners to quickly catch the idea, and maybe extend the article to some of the most popular array methods as well.

Collapse
 
baenencalin profile image
Calin Baenen

I should start making comprehensive guides, so I can gain popularity, since my YT career's dead.

Collapse
 
hellnar profile image
Stas Klymenko

It's better to use Reduce for this task.

Collapse
 
mehuljariwala profile image
Mehul Jariwala

const fruits = ["banana", "apple", "pear"];
fruits.reduce((initalArr, value, currentIndex) => {
initalArr.push(${currentIndex} --- ${value});
return initalArr;
}, []);

Thread Thread
 
aminnairi profile image
Amin

Well, if you are going with Array.prototype.reduce, you better be not using any side-effects.

const root = document.getElementById("root");

if (!root) {
  throw new Error("Root not found");
}

const fruits = ["banana", "apple", "pear"];

const innerHTML = fruits.reduce((html, fruit, index) => {
  return `${html}#${index + 1}: ${fruit}<br>`;
}, "");

root.innerHTML = innerHTML;
Enter fullscreen mode Exit fullscreen mode
Collapse
 
suprabhasupi profile image
Suprabha

It's a common mistake that devs do sometimes, and the above example suits here, Thanks for sharing this ☺️

Collapse
 
devfranpr profile image
DevFranPR

I can't! It's start using it and ... look at this one liners πŸ₯΄

Collapse
 
alfredosalzillo profile image
Alfredo Salzillo

In your last example the forEach is the wrong choice. A reduce would have been better

Collapse
 
seven_77 profile image
Seven

do agree

Collapse
 
suprabhasupi profile image
Suprabha

Yeah, my main POC was to use map method wisely. Try to use other array methods.

Collapse
 
alfredosalzillo profile image
Alfredo Salzillo

Yeah, but a map used wisely would have been better than the for, wrong example

const text = array.map((e, i) => [e,i].join(':')).join('<br>')
Enter fullscreen mode Exit fullscreen mode
Collapse
 
yankzy profile image
Yankuba Kuyateh

With innerHTML you are vulnerable to XSS attack. Just be aware.

Collapse
 
adam_cyclones profile image
Adam Crockett πŸŒ€

innerText πŸ”’

Collapse
 
matthewbdaly profile image
Matthew Daly

I disagree somewhat. While the correct use case for map() is for when you want to transform the items in an array, and you shouldn't use it if you're just carrying out an action on each item, these days loops (as opposed to the forEach() method) are best avoided for most use cases, particularly when using a UI library like React.

Using chainable array methods like map() and forEach() has numerous advantages over a loop:

  • It breaks your code into a series of steps, making it easier to understand and reason about than nested loops
  • Because the callback for each is a function, you can add type hints for the parameters and return value when using Flow or Typescript to help document what each item represents
  • It mitigates the need for multiple levels of indentation

Yes, if you're not changing the data, you should use forEach() rather than map(), but in code reviews I would actively discourage using a loop if you can use forEach() instead.

Collapse
 
danielvandenberg95 profile image
DaniΓ«l van den Berg

Reduce would be best for the first example.

Collapse
 
eyal1990 profile image
Eyal Ofri

If you're using ESLint you can enforce this behavior by using the rule "array-callback-return":
eslint.org/docs/2.0.0/rules/array-...

Collapse
 
adam_cyclones profile image
Adam Crockett πŸŒ€ • Edited

GC good at cleaning up orphaned things in memory, perhaps this is my head cannon talking, but I trust that in memory non memory critical applications (99% of cases, not running on a Saga Saturn), map is just fine. I don't have a problem using array.map because the old array will likely get cleared up sooner or later

Collapse
 
deathshadow60 profile image
deathshadow60

I think your first example has the map and innerHTML backwards.

Both map and foreach far too often waste memory and execution time. I've dealt with so many codebases lately where people are making copies of copies of copies of arrays wasting so much memory and time it drags performance down noticeably for users. It also doesn't help that since these are all callback driven that means the overhead of functions for each and every iteration.

I'm not THAT familiar with JavaScript internals, but if this were a compiled language the assembly used for a function call -- inc SP to make room for vars, pusha, push args, , move copy of stack pointer into base pointer, do your function stuff. then popa and retf de-allocating the locals and arguments... I can only imagine the horror-show that must be in an interpreted language.

And for what? "Wah wah eye dunz wunna yuz teh four loupe?". I look at the crazy hoops a lot of people will go through just to avoid it, and it's utterly nutters.


const fruits = ["apple", "orange", "cherry"];
let text = "";
for (let fruit of fruits) text += fruie;
document.getElementById("main").textContent = text;

Not that one would do that in real life, given the power of Array.join.

Laugh is, I suggested using for/of on another site, and someone said "stop being stuck in the past, for loops are ancient"... IT's like "hey bozo, for/of is newer than Array.foreach" I mean For/of seems like it was created for the explicit purpose of being a more efficient method than Array.foreach!

But don't try to argue with the "every line needs to be its own function, for/if/swtich/case are teh evilz" folks.

But what do I know, I'd have coded your final example as:


// assuming main is empty

const
    fruits = ["apple", "orange", "cherry"],
    main = document.getElementByID("main");
    
for (let i = 0, fruit; fruit = fruits[i]; i++) main.append(
    i, ": ", fruit, document.createElement("br")
);

Since assignment as the comparison results in the fastest loop, given you have no -- and likely wouldn't have -- loose false values in the array. Also, append is awesome. Be even more awesome if it included references to the nodes it created.

And I trust innerHTML with data about as far as I could throw the USS Iowa. YMMV.

Collapse
 
narasimha1997 profile image
Narasimha Prasanna HN

But yeah it is immediately garbage collected by V8s GC. But still, using map is not recommended for larger arrays, because you may need lot of heap memory at that point in time before it is garbage collected.

Collapse
 
jakecarpenter profile image
Jake Carpenter

Getting a new array is very much the point. We do this to avoid side effects that are difficult to track. It’s the same reason functions should return a value, not modify a reference.

Immutability by default is a solid strategy that helps avoid countless bugs. Only modify the original array when you have proven map to be a performance bottleneck - and it’s rare.

Collapse
 
cess11 profile image
PNS11

As an alternative to the first example I would propose Array.prototype.join(), i.e. remove the text variable and set the HTML to fruits.join(''). In well structured code scope and GC will clean up the fruits array when appropriate.

It's common to have use for both the old array and the new one, e.g. for time travel through app state or when both sets might get rendered depending on user input. When building complex applications one also tends to prefer to avoid data mutations to make code more readable and easier to debug, functional mapping tends to be appropriate for this purpose.

Collapse
 
hellnar profile image
Stas Klymenko

map - if you expect an array as a result.
reduce - if you expect one value as a result.
forEach - if you don't need to return a result. Better for sync code.
for of - if you don't need to return a result and you might break the loop. Better for async code.

Collapse
 
drarig29 profile image
Corentin Girard

Note that you can use functions like Promise.all() with map() too.

Some comments have been hidden by the post's author - find out more