26

For eg:

var persons = [{ "name":"A", "salary":1200 }, { "name":"B", "salary":"1500" }];

And you want to change the value of "salary" of each person in an original array.

Maxgrid
  • 313
  • 1
  • 3
  • 9
  • 3
    In addition to the answers: `map` very deliberately _always_ creates a new array, see "Return value" on https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map -- it is taken from the functional programming context and immutability of the original structure is a feature. On parallel systems [(such as Spark)](http://data-flair.training/blogs/spark-rdd-operations-transformations-actions/) `map` would be used to distribute work to nodes: each map-function is executed on a different system. – Mörre Oct 02 '17 at 07:07
  • you can make use of the second parameter thisArg but that would be equivalent to forEach – stackoverflow Oct 02 '17 at 07:11
  • 1
    Possible duplicate of [is it possible to change values of the array when doing foreach in javascript?](https://stackoverflow.com/questions/12482961/is-it-possible-to-change-values-of-the-array-when-doing-foreach-in-javascript) – Mörre Oct 02 '17 at 07:18

10 Answers10

46

If you want to mutate the original array, you can use Array#forEach function.

const persons = [{ "name":"A", "salary":1200 }, { "name":"B", "salary": 1500 }];

persons.forEach(item => item.salary += 1000);

console.log(persons)

Array#map creates a new array of the created items and returns that. After you need to assign the returned result.

let persons = [{ "name":"A", "salary":1200 }, { "name":"B", "salary": 1500 }];

persons = persons.map(item => {
  item.salary += 1000;
  return item;
});

console.log(persons);
Chloe
  • 25,162
  • 40
  • 190
  • 357
Suren Srapyan
  • 66,568
  • 14
  • 114
  • 112
  • What do you mean with *"if its items are reference types"*? The same logic applies no matter what you keep in the array. – Etheryte Oct 02 '17 at 07:09
  • 7
    If you have an array of primiives and you want to change those values inside the forEach, you will get copies of them and the actual array items will not be changed – Suren Srapyan Oct 02 '17 at 07:12
  • 1
    you can use forEach with primitive if you add second argument to callback function and use `persons[i] += 10` it will be the same as `for` loop. – jcubic Oct 02 '17 at 08:34
  • 1
    In that case, yes you can – Suren Srapyan Oct 02 '17 at 09:12
  • 2
    For `map`, even if not re-assigning to `persons` variable, and printing in console, giving same result as `forEach`, probably due to the fact that object is passed by reference? – Sandeep Kumar Aug 21 '19 at 13:15
  • @SandeepKumar Yes, `forEach` works cause the passed parameter is of reference type – Suren Srapyan Aug 21 '19 at 13:31
  • What happens if someone use map() but not assign the returned array to a variable? does it create infant unallocated array in memory? Is it a memory leak? – user2734550 Jun 10 '20 at 22:33
  • @user2734550 New array will be created and then be deleted by Garbage Collector. Generally, memory leak is about having an object, which will not be deleted during the session – Suren Srapyan Jun 11 '20 at 06:03
10

You can mutate the objects directly iterating with map. If I understood you correctly.

persons.map(i => { i.salary = i.salary * 1.25; return i; });
console.log(persons);
// [{ "name":"A", "salary": 1875 }, { "name":"B", "salary": 2343.75 }]

Though it's anti-pattern and you should avoid performing mutations of your original array in map().

Penny Liu
  • 15,447
  • 5
  • 79
  • 98
terreb
  • 1,417
  • 2
  • 23
  • 40
  • 2
    This answer is totally correct, so I voted. Why put a negative vote? Avoid mutating is an option not a rule. – JohnPan Jul 18 '19 at 14:14
  • 4
    @JohnPan it's considered an anti-pattern using the map function without actually needing the result. – acme Aug 26 '20 at 13:46
3

I read other answers, you can use any of them, but I see some problems there.

I will mention 2 methodologies I have used in many different languages, map and forEach. map is a functional way of traversing a collection and creating some new collection with new (different or same) elements, independent of languages. With map, it is expected to create a new collection that is created by some mapping from initial collection. On the other hand, forEach is a method that eases traversing a collection by not using usual for loop syntax for collections, and mutating (or changing) each item if desired.

If you use map on a collection that contains objects, and change those objects in the mapper function, you might face with unexpected behavior. Beacuse you are changing directly the object you are operating on, and do not mapping it to another object. This object might can be considered as a state and computers works based on the state transfers. If you want to change that object, i.e. some state, it is absolutely ok, but based on the description, you should not use map for such a case. Because you are not creating a new array with some new values, but instead, mutating provided elements. Use forEach for such a case.

I have added an example here. You can click the link and take a look at the console, and see my what I mean in a more clear way.

As far as I know, based on my experience, mutations in map method is considered as bad practice and discouraged.

These two are added for different purposes and it would be better to use them as expected.

For more, see Mozilla Web Docs page for Array.

safakeskin
  • 628
  • 5
  • 16
3

Use forEach. If your array is full of objects, and you simply want to mutate those objects — like in the original question — then you can simply have your callback function mutate the item passed to it in its first argument.

If your array is full of primitives, which can only be changed by assigning something else to the array slots, thereby mutating the array — or if for some other reason you want to reassign things to the array slots — you can still use forEach. The second parameter and third parameters passed to the callback are the array index of the element currently being operated on, and a reference to the array itself. So within the callback function, you can assign to the relevant array slot.

2

you can use a simple for loop for that

var persons = [{ "name":"A", "salary":1200 }, { "name":"B", "salary":"1500" }];

for(let element of persons){
    element.salary*=2;
}

console.log(persons);
marvel308
  • 10,288
  • 1
  • 21
  • 32
2

.map() function takes third parameter in its callback thats the instance of original array.

You could do something like this also:

var persons = [{ "name":"A", "salary":1200 }, { "name":"B", "salary":1500 }];

persons.map(function(person, key, array) {
  array[key].salary *= 2;
});

console.log(persons);
Maxgrid
  • 313
  • 1
  • 3
  • 9
  • 4
    Bad practice - use `forEach`. Yes you can use `reduce` or `map` for everything that you can do with `forEach` or a for loop - but that does not mean you should. There is a reason there are different functions, even if they overlap. Reading code should not be made harder than it is. People familiar with the deeper concepts behind the different functions will be lead astray unless they pay extra attention (and people unfamiliar won't gain anything). See my comment under the question for the context. – Mörre Oct 02 '17 at 07:16
2

JavaScript has an inbuilt Array method map that iterate the values of an Array

persons.map(person => person["salary"] + 1000)
Philzace
  • 246
  • 2
  • 5
1

var persons = [{ "name":"A", "salary":1200 }, { "name":"B", "salary":"1500" }];

var mutatedPersons = persons.map(function(obj){
   return {name:obj.name,salary:parseInt(obj.salary) + 100};
})

console.log(mutatedPersons);
Miguel Coder
  • 1,896
  • 19
  • 36
1

try:

let persons = persons.map((person) => {person['salary'] = parseInt(person['salary']) + 1; return person})
  • parseInt as you have string value as salary. – Siddhant Shrivastav Jun 06 '20 at 15:44
  • 1
    While this code may resolve the OP's issue, it is best to include an explanation as to how your code addresses the OP's issue. In this way, future visitors can learn from your post, and apply it to their own code. SO is not a coding service, but a resource for knowledge. Also, high quality, complete answers are more likely to be upvoted. These features, along with the requirement that all posts are self-contained, are some of the strengths of SO as a platform, that differentiates it from forums. You can edit to add additional info &/or to supplement your explanations with source documentation – ysf Jun 06 '20 at 21:48
0

If you have an array of primitives, you can use this function:

function mapInplace<T>(arr: T[], callback: (v: T, i: number) => T) {
    for(const [i, v] of arr.entries()) {
        arr[i] = callback(v, i)
    }
}

Example usage:

mapInplace(weights, w => w / total)

There's no return value since it's mutating the array.

mpen
  • 272,448
  • 266
  • 850
  • 1,236