JavaScript: Difference between .forEach() and .map()
Asked Answered
G

16

251

I know that there were a lot of topics like this. And I know the basics: .forEach() operates on original array and .map() on the new one.

In my case:

function practice (i){
    return i+1;
};

var a = [ -1, 0, 1, 2, 3, 4, 5 ];
var b = [ 0 ];
var c = [ 0 ];
console.log(a);
b = a.forEach(practice);
console.log("=====");
console.log(a);
console.log(b);
c = a.map(practice);
console.log("=====");
console.log(a);
console.log(c);

And this is output:

[ -1, 0, 1, 2, 3, 4, 5 ]
=====
[ -1, 0, 1, 2, 3, 4, 5 ]
undefined
=====
[ -1, 0, 1, 2, 3, 4, 5 ]
[ 0, 1, 2, 3, 4, 5, 6 ]

I can't understand why using practice changes value of b to undefined.
I'm sorry if this is silly question, but I'm quite new in this language and answers I found so far didn't satisfy me.

Glanti answered 22/12, 2015 at 23:54 Comment(8)
It’s this simple: .map returns a new array, whereas .forEach doesn’t return anything. Basically, if you want to obtain a modified form of the previous array, you use .map, if you don’t want that, you use .forEach.My
Possible duplicate of what use does the javascript forEach method have (that map can't do)?My
@Xufox - I red this topic before creating new one, but answer didn't satisfiy me.Glanti
Don’t just say it didn’t satisfy you. How exactly doesn’t it answer your question (have you read all the answers?)? What is your specific question that isn’t covered by the proposed duplicate target?My
@Xufox That question deals with self-implemented functions, and is not really about the standardized ES5 functions.Mines
See the article JavaScript — Map vs. ForEachRevelationist
See also the language-agnostic Is there a difference between foreach and map?Trivium
I'm not sure it's correct to say that forEach operates on the original array. I believe neither modifies the original array.Chevron
M
343

They are not one and the same. Let me explain the difference.

forEach: This iterates over a list and applies some operation with side effects to each list member (example: saving every list item to the database) and does not return anything.

map: This iterates over a list, transforms each member of that list, and returns another list of the same size with the transformed members (example: transforming list of strings to uppercase). It does not mutate the array on which it is called (although the callback function may do so).

References

Array.prototype.forEach() - JavaScript | MDN

Array.prototype.map() - JavaScript | MDN

Misusage answered 22/12, 2015 at 23:56 Comment(4)
map return list and forEach not . OKCirilo
One extra thing to keep in mind if you encounter a codebase with .maps instead of .forEach's: IE <=10 does not support the .forEach, so a much used workaround is to use .map insteadGrabowski
Are you sure that forEach modifies the original array?Chevron
@johnywhy Where in the answer does it state that?Brittenybrittingham
M
108
  • Array.forEach “executes a provided function once per array element.”

  • Array.map “creates a new array with the results of calling a provided function on every element in this array.”

So, forEach doesn’t actually return anything. It just calls the function for each array element and then it’s done. So whatever you return within that called function is simply discarded.

On the other hand, map will similarly call the function for each array element but instead of discarding its return value, it will capture it and build a new array of those return values.

This also means that you could use map wherever you are using forEach but you still shouldn’t do that so you don’t collect the return values without any purpose. It’s just more efficient to not collect them if you don’t need them.

Mines answered 23/12, 2015 at 0:0 Comment(7)
Of note: in 2015, it would have been arguable that forEach would have "been more efficient" than map especially if a polyfill was required to support forEach on an older browser (IE8 or 9). You don't need to assign the return of map to anything; the return value should get garbage collected immediately after map returns when the return of map is not assigned.Parcenary
@Parcenary Just because something is garbage collected immediately, that does not mean that you are not getting hit by the allocations that were necessary. So forEach will conceptually still be more efficient and better suited for tasks where you do not need to collect results. And I don’t know about you but in 2015, I was not developing for IE8 anymore (which btw. also didn’t support map); and IE9+ support forEach. And actually a month after my answer, Microsoft ended support for those browsers.Mines
Are both forEach and map guaranteed to process the elements in the same order?Hobbema
@Quentin2 Yeah, also, both functions are synchronous, so map and forEach calls will only return once the whole array has been looped through and the callback has been called for each.Mines
If you use map in place of forEach, you're not "collecting" anything. So what's the harm?Chevron
@Mines "forEach will conceptually still be more efficient" -- Does anyone have any statistics to support that?Chevron
@johnywhy The better question is how does abusing map benefit you?Brittenybrittingham
N
82
forEach() map()
Functionality Performs given operation on each element of the array Performs given "transformation" on a "copy" of each element
Return value Returns undefined Returns new array with transformed elements, leaving back original array unchanged.
Preferrable usage scenario and example Performing non-tranformation like processing on each element.

For example, saving all elements in the database.
Obtaining array containing output of some processing done on each element of the array.

For example, obtaining array of lengths of each string in the array

forEach() example

chars = ['Hello' , 'world!!!'] ;
    
var retVal = chars.forEach(function(word){
  console.log("Saving to db: " + word) 
})
  
console.log(retVal) //undefined

map() example

 chars = ['Hello' , 'world!!!'] ;
    
 var lengths = chars.map(function(word){
   return word.length
 }) 
    
 console.log(lengths) //[5,8]
Nook answered 29/3, 2018 at 6:56 Comment(0)
C
26

The main difference that you need to know is .map() returns a new array while .forEach() doesn't. That is why you see that difference in the output. .forEach() just operates on every value in the array.

Read up:

You might also want to check out: - Array.prototype.every() - JavaScript | MDN

Cheng answered 22/12, 2015 at 23:57 Comment(0)
G
15

Performance Analysis For loops performs faster than map or foreach as number of elements in a array increases.

let array = [];
for (var i = 0; i < 20000000; i++) {
  array.push(i)
}

console.time('map');
array.map(num => {
  return num * 4;
});
console.timeEnd('map');


console.time('forEach');
array.forEach((num, index) => {
  return array[index] = num * 4;
});
console.timeEnd('forEach');

console.time('for');
for (i = 0; i < array.length; i++) {
  array[i] = array[i] * 2;

}
console.timeEnd('for');
Garbanzo answered 23/5, 2019 at 12:20 Comment(4)
Here is the result on my computer: map: 1642ms forEach: 885ms for: 748msVin
This test is not very scientific. It'd need to test them all doing the same thing. map is building an array, foreach is editing an array in place, and the for loop is modifying the other array in place also. When I modify the tests to actually do the same thing, map is faster than foreach.Glycosuria
I would argue it is scientific when used for the case of "I need to do something to each array element, what should I use?" question. For a direct comparison of all the operations then you're right, but for people who come here asking if map is quicker than forEach for just looping, this is a valuable answer.Unbelt
@Glycosuria wins this debate. I came to this page wondering if i can use map in place of forEach without sacrificing performance. The answer, if Anther's results are accurate, is "yes".Chevron
H
10

forEach() :

  • return value : undefined

  • originalArray : not modified after the method call

  • newArray is not created after the end of method call.


map() :

  • return value : new Array populated with the results of calling a provided function on every element in the calling array

  • originalArray : not modified after the method call

  • newArray is created after the end of method call.


Conclusion:

Since map builds a new array, using it when you aren't using the returned array is an anti-pattern; use forEach or for-of instead.

Hurtful answered 24/7, 2020 at 9:54 Comment(1)
Based on reading this page, it seems there's no downside to using .map for everything. It's fewer characters to type, loops at least as fast as .forEach, and then i can just remember one method.Chevron
H
10

map returns a new array.

forEach has no return value.

That's the heart of the difference. Most of the other answers here say effectively that, but in a much more convoluted way.

Huberthuberto answered 13/4, 2021 at 1:34 Comment(0)
S
9

forEach: If you want to perform an action on the elements of an Array and it is same as you use for loop. The result of this method does not give us an output buy just loop through the elements.

map: If you want to perform an action on the elements of an array and also you want to store the output of your action into an Array. This is similar to for loop within a function that returns the result after each iteration.

Hope this helps.

Salmanazar answered 11/9, 2017 at 12:50 Comment(0)
L
6

The difference lies in what they return. After execution:

arr.map()

returns an array of elements resulting from the processed function; while:

arr.forEach()

returns undefined.

Latinalatinate answered 8/9, 2017 at 13:40 Comment(0)
P
4

Difference between forEach() & map()

forEach() just loop through the elements. It's throws away return values and always returns undefined.The result of this method does not give us an output .

map() loop through the elements allocates memory and stores return values by iterating main array

Example:

   var numbers = [2,3,5,7];

   var forEachNum = numbers.forEach(function(number){
      return number
   })
   console.log(forEachNum)
   //output undefined

   var mapNum = numbers.map(function(number){
      return number
   })
   console.log(mapNum)
   //output [2,3,5,7]

map() is faster than forEach()

Phylum answered 23/9, 2019 at 11:49 Comment(1)
How do you know map is faster than forEach?Chevron
C
3

One thing to point out is that both methods skips uninitialized values, but map keeps them in the returned array.

var arr = [1, , 3];

arr.forEach(function(element) {
    console.log(element);
});
//Expected output: 1 3

console.log(arr.map(element => element));
//Expected output: [1, undefined, 3];
Chadbourne answered 12/9, 2019 at 11:48 Comment(1)
In Node.js v14.15.0, the output of console.log(arr.map(element => element)); is [ 1, <1 empty item>, 3 ].Ablative
D
3

Diffrence between Foreach & map :

Map() : If you use map then map can return new array by iterating main array.

Foreach() : If you use Foreach then it can not return anything for each can iterating main array.

useFul link : use this link for understanding diffrence

https://codeburst.io/javascript-map-vs-foreach-f38111822c0f

Disappoint answered 28/9, 2019 at 16:4 Comment(0)
H
3

One of the subtle differences not mentioned here is that forEach() can loop over a static (not live) NodeList while map() cannot

Works perfectly:

document
    .querySelectorAll('.score')
    .forEach(element=>console.log(element));

Uncaught "TypeError: document.querySelectorAll(...).map is not a function":

document
    .querySelectorAll('.score')
    .map(element=>console.log(element));
Hothead answered 7/9, 2021 at 9:52 Comment(19)
The NodeList returned by querySelectorAll() is not an array. It happens to forEach(). That imply that 1. a NodeList has to implement a .map() methid. It is perfectly fine it it doesn't. 2. It doesn't imply that map() cannot loop over a NodeList - the .map() method is generic and applicable to any array-like, so Array.prototype.map.call( document.querySelectorAll(".score"), element=>console.log(element) ) would work.Isooctane
@Isooctane Your comment is unclear. Can .map iterate over nodes or not? Is the code in this answer wrong?Chevron
@johnywhy "Can .map iterate over nodes or not?" yes, it can. I've demonstrated how. "Is the code in this answer wrong?" the code - no. Well, except document.querySelectorAll('.score').map(element=>console.log(element)); but it does mention it throws an error. The text is wrong. NodeList and arrays both have a .forEach(). Trying to call a method with the same name on two different objects, doesn't imply which object the method can operate on. So, the error is not related to .map() itself but because to NodeList. And array's .map() can be applied to NodeLists.Isooctane
@Isooctane Thx! So you agree that map can be used instead of forEach in all cases?Chevron
@johnywhy no, I don't. Only use it when you do mapping. Don't use it when you don't do mapping. Use a loop or .forEach for those.Isooctane
@Isooctane Why? What's the impact on code, readability, performance, etc?Chevron
@johnywhy Is performing a mapping operation without using returned value an antipattern?. Performance is indeed one aspect. But readability is a very big other aspect. Overall, you can use a hammer to spread butter on your sandwich but the performance and maintainability of that sandwitch would not be the same as if you used a knife.Isooctane
@Isooctane According to tests performed by a few people on this page, map will perform at least as fast as forEach, or faster. So if performance is the question, map is equal to or better than forEach. What do you mean about "maintainability"?Chevron
@johnywhy the tests probably don't account for GC runs afterwards. As for maintainability - do you reckon it's completely reasonable and expected person.getName() will delete the person? Because I personally don't. And for the very same reason, I don't think arr.map() is maintainable if it doesn't do mapping. Breaks expectations, misuses idioms, it's hard to reason about and potentially refactor, without being thoroughly familiar with details that are supposed to be abstracted away.Isooctane
@Isooctane person.getName() will delete the person?Chevron
@johnywhy example analogous to using .map() for operations that aren't mapping. Normally, the expectation is that getX will not change anything and just give you X. Similar to how .map() sets up the expectation that a transformation is being made and it would give you the transformed values. You seem surprised indicating that your expectation for person.getName() is subverted. Same thing happens when .map() is misused. Subverted expectations. As I said, it makes the code harder to reason about.Isooctane
@Isooctane Bad comparison. map doesn't delete, modify, or damage anything. You could also create a new array using forEach instead of map, and it would be valid code. map just makes it a bit easier.Chevron
@johnywhy no, it's a very apt comparison. It's not supposed to. The same way getName() also not supposed to. You yourself suggested that it's interchangeable with .forEach() which then means that mutation is to be tolerated, yet it goes counter to what mapping is. I really don't think this is getting anywhere as you seem to be trying to deliberately ignore what I'm saying. So, here is hopefully the last thing to say: If you tolerate code like arr.map(x => { arr.shift() }) that's on you, just know you're wrong for doing so.Isooctane
i'm listening very carefully to what you're saying, and you seem to be making a false statement. You're asserting that if map is used instead of forEach, the array will definitely get mutated. That seems obviously false. Neither function, map or forEach mutate the original array. Before map or forEach existed there wasn't any loop statement which returned an array.Chevron
forEach could be used to mutate the original array, same as map. No difference.Chevron
@johnywhy No, I'm not saying that using .map() will mutate the array. I said it shouldn't be used when not doing a mapping operation. You disagreed with that. Thus you are saying that .map() should be used for non-idiomatic purpose. The entire point with getName() is that - using a non-idiomatic code hurts the clarity.Isooctane
"forEach could be used to mutate the original array, same as map. No difference" the only valid .forEach() call is one that has side-effects. This is quite different to the idiomatic .map() call which doesn't. Just how getName() would idiomatically not have side-effects.Isooctane
Aside from map and forEach, there are myriad functions one can create, some which return something, some which don't, some which have side-effects, some which don't, with no clues given to someone reading the code (like "oh, they're using map, so this is supposed to return an array"). In myriad cases, there are no available clues as to whether or not a function returns something other than reading the code and comments. So it seems a bit absurd to be so strict about this one limited case (map vs forEach) when so much other code doesn't offer such signposts.Chevron
@Isooctane I'm playing devil's advocate here, but sincere. Using map instead of forEach appeals because that simplifies my coding effort. You're insisting to use a less performant, less capable iterator, simply for self-documentation. But self-documentation is about meaningful variable names and function names supported by rich commenting, which I already do. In some languages, there's only ONE iterator -- people manage. sitepoint.com/self-documenting-javascriptChevron
W
2

.map and .forEach will do just about then same thing, until you start operating on arrays with millions of elements. .map will create another collection with the same size (and possibly type, depending on the array species) which could use up a LOT of memory. .forEach will not do this.

Willywilly answered 9/4, 2021 at 8:22 Comment(2)
I specified that difference above.Willywilly
@Huberthuberto this answer seems accurate to me.Chevron
E
1

Performance Analysis (again - not very scientific)
In my experience sometime .map() can be faster than .foreach()

let rows = [];

    for (let i = 0; i < 10000000; i++) {
      // console.log("here", i)
      rows.push({ id: i, title: 'ciao' });
    }

    const now1 = Date.now();

    rows.forEach(row => {
      if (!row.event_title) {
        row.event_title = `no title ${row.event_type}`;
      }
    });

    const now2 = Date.now();

    rows = rows.map(row => {
      if (!row.event_title) {
        row.event_title = `no title ${row.event_type}`;
      }
      return row;
    });

    const now3 = Date.now();

    const time1 = now2 - now1;
    const time2 = now3 - now2;
    console.log('forEach time', time1);
    console.log('.map time', time2);

On my macbook pro (late 2013)

  • forEach time 1909
  • .map time 444
Eulaliaeulaliah answered 14/7, 2022 at 7:43 Comment(1)
It's great to have these stats! At the moment, based on what i've read here, it seems i can just use .map in place of .forEach as standard practice. One question is: can map and forEach both iterate over nodes?Chevron
B
-3

Map implicitly returns while forEach does not.

This is why when you're coding a JSX application, you almost always use map instead of forEach to display content in React.

Blancablanch answered 22/3, 2020 at 17:38 Comment(1)
No, this is completely wrong as of this writing. map does not "implicitly return", whatever that means. Instead, it explicitly returns a new array.Huberthuberto

© 2022 - 2024 — McMap. All rights reserved.