27

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.

3

11 Answers 11

51

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);

Sign up to request clarification or add additional context in comments.

8 Comments

What do you mean with "if its items are reference types"? The same logic applies no matter what you keep in the array.
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
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.
In that case, yes you can
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?
|
11

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().

2 Comments

This answer is totally correct, so I voted. Why put a negative vote? Avoid mutating is an option not a rule.
@JohnPan it's considered an anti-pattern using the map function without actually needing the result.
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.

Comments

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.

Comments

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);

Comments

2

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

persons.map(person => person["salary"] + 1000)

Comments

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);

Comments

1

.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);

2 Comments

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.
This works, but it has the unintended side-effect that map always returns a new array of the same length as the source array. You're not doing anything with it, but it still gets allocated and promptly thrown away, which is unnecessary work that may slow your webapp down if these arrays are big.
1

try:

let persons = persons.map((person) => {person['salary'] = parseInt(person['salary']) + 1; return person})

2 Comments

parseInt as you have string value as salary.
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
1

yes it's pretty easy when all you want to do is to change the properties of the objects in array but here's another way that's like almost assigning a new array and not losing the actual reference to it.

let arr = [2, 3, 4, 5]
arr.splice(0, arr.length, ...arr.map(k => k + 10))
console.log(arr)

Comments

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.