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 );
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]
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>";
}
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!
Latest comments (30)
This is cool, I worked on a project that i could see map() everywhere for no reason! As you said, when its working with small data, its fine to use it. But when have a massive amount of data, its complicated. Even more complicated when use micro services and the communication between the services is async. Take aaaages to load.
So basically: "don't be stupid, use the right tool for the job". Duh... really?!
I have a question - aren't you doing code reviews in your company? Why do you need to write an article just to point out to newbies, that besides Array.map they have to learn what other methods exist and use them properly?
Oh and give a ridiculous example that is accessing a variable outside the function AND the foreach statement, when all you need in this case is Array.reduce:
Please take some time to study what other options you have before writing articles.
Hard disagree. As others have said, the string concatenation example should have been
reduce
instead of map, but always favor immutable, functional operations over procedural ones because it is so much easier to introduce bugs in procedural operations like for loops.Memory consumption is rarely a factor in most JavaScript apps, and garbage collectors get better every year. This is a classic example of a premature optimization. It's better to use
map
(andreduce
!) for pretty much everything, and then go back and optimize into loops where you know there are bottlenecks, after your codebase is more mature.You missed the point of the article I think. The whole point of the article is to say that semantically, a
map()
should be stored in a variable because it creates a new array. And that if you don't care about the result and just want to do side-effects in a "functional" way (here, I use the word "functional" as opposited to with an actual for-loop statement), just useforEach()
instead.Yes, sometimes
reduce()
will be better and you should refactor to use it, but that's not the point here.And yes, the argument of memory consumption was a bad way to try giving a reason not to not store the result of a
map()
.Totally make sense, I also used to point out this in code reviews.
So first complete the task and then refactor it accordingly.
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.
Note that you can use functions like
Promise.all()
withmap()
too.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.
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.
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.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.
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:
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.
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
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-...
Reduce would be best for the first example.
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 theforEach()
method) are best avoided for most use cases, particularly when using a UI library like React.Using chainable array methods like
map()
andforEach()
has numerous advantages over a loop:Yes, if you're not changing the data, you should use
forEach()
rather thanmap()
, but in code reviews I would actively discourage using a loop if you can useforEach()
instead.With innerHTML you are vulnerable to XSS attack. Just be aware.
innerText
πIn your last example the forEach is the wrong choice. A reduce would have been better
Yeah, my main POC was to use map method wisely. Try to use other array methods.
Yeah, but a map used wisely would have been better than the for, wrong example
do agree
I can't! It's start using it and ... look at this one liners π₯΄
Some comments have been hidden by the post's author - find out more