Copy array of objects and make changes without modifying original array
Asked Answered
H

5

11

I have an array of objects. I would like to deep copy the array of objects and make some changes to each object. I want to do this without modifying the original array or original objects that were in that array.

This is the way I have done it. However, being new to JavaScript I want to make sure this is a good approach.

Is there a better way to do this?

const users = 
[
    {
        id       : 1,    
        name     : 'Jack',
        approved : false
    },
    {
        id       : 2,    
        name     : 'Bill',
        approved : true
    },
    {
        id       : 3,    
        name     : 'Rick',
        approved : false
    },
    {
        id       : 4,    
        name     : 'Rick',
        approved : true
    }
];


const users2 = 
    users
        .map(
            (u) => 
            {
                return Object.assign({}, u);
            }
        )    
        .map(
            (u) => 
            {
                u.approved = true;
                return u;
            }
        );    


console.log('New users2 array of objects:')
console.log(users2);

console.log('This was original users array is untouched:')
console.log(users);

Output:

New users2 array of objects:
[ { id: 1, name: 'Jack', approved: true },
  { id: 2, name: 'Bill', approved: true },
  { id: 3, name: 'Rick', approved: true },
  { id: 4, name: 'Rick', approved: true } ]
This was original users array is untouched:
[ { id: 1, name: 'Jack', approved: false },
  { id: 2, name: 'Bill', approved: true },
  { id: 3, name: 'Rick', approved: false },
  { id: 4, name: 'Rick', approved: true } ]
Harrisharrisburg answered 4/8, 2017 at 17:46 Comment(1)
for just a copy, you could use JSON.stringify and JSON.parse.Wahhabi
W
23

For a single pass, you could use Object.assign with the changed property as well.

const users = [{ id: 1, name: 'Jack', approved: false }, { id: 2, name: 'Bill', approved: true }, { id: 3, name: 'Rick', approved: false }, { id: 4, name: 'Rick', approved: true }];
const users2 = users.map(u => Object.assign({}, u, { approved: true }));

console.log(users2);
console.log(users);
.as-console-wrapper { max-height: 100% !important; top: 0; }

UPDATE with spreading properties.

const users = [{ id: 1, name: 'Jack', approved: false }, { id: 2, name: 'Bill', approved: true }, { id: 3, name: 'Rick', approved: false }, { id: 4, name: 'Rick', approved: true }];
const users2 = users.map(u => ({ ...u, approved: true }));

console.log(users2);
console.log(users);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Wahhabi answered 4/8, 2017 at 17:51 Comment(0)
R
6

Yes that looks good. You could also perform the modification when you are cloning, in order to avoid mapping over the array twice.

const users2 = users.map((u) => {
    const copiedUser = Object.assign({}, u);
    copiedUser.approved = true;
    return copiedUser;
}); 
Radferd answered 4/8, 2017 at 17:50 Comment(0)
G
6

I prefer JSON.stringify and JSON.parse

var users = [ { id: 1, name: 'Jack', approved: false },
{ id: 2, name: 'Bill', approved: true },
{ id: 3, name: 'Rick', approved: false },
{ id: 4, name: 'Rick', approved: true } ];

// user2 will be copy of array users without reference
var users2 = JSON.parse(JSON.stringify(users));
Gothicize answered 2/10, 2018 at 12:27 Comment(2)
explanation: This successfully strips the reference to original Object when creating the JSON string. Strings are stored by value so it has no reference.Lefton
This fails with any value that's unsupported in JSON, like Date objects, Functions, etc. See this answer which explains the downsidesPraenomen
A
0

There are a few ways to copy a array in javascript, i believed that the most used are:

  • slice()
  • Array.from()

The slice function will return a portion (or all content) of a given array as a new array, based at a begin and end index (begin and end index are optional):

const a = [1,2,3,4,5,6,7,8,9]
/*
* Only begin index
*/
const b = a.slice(2)
console.log(b) //Will Print [3,4,5,6,7,8,9]
/*
* Begin index and end index
*/
const c = a.slice(5,8)
console.log(c) //Will Print [6,7,8]
/*
* No indexes provided
*/
const d = a.slice()
console.log(d) //Will print [1,2,3,4,5,6,7,8,9]

Array.from() is a function that will create a new array from an array-like or iterable parameters.

const a = Array.from('bar');
console.log(a) //Will Print ["b","a","r"]
const b = ["for","bar"];
const c = Array.from(b);
console.log(c) //Will print  ["for","bar"]

More about slice

More about Array.from()

Alleman answered 4/8, 2017 at 18:9 Comment(0)
S
0

In React JS I tried most ways of copying and modifying the newly copied array but it still modified the original array. The methods I tried are slice Array.from for loop spread operator, all this ended up modifying the original array. The solution was, stringify the original array and assign it to a new variable, then parse the variable to get a fresh copy without reference as stated by @Roman Yakoviv above.

Switzer answered 23/8, 2022 at 14:36 Comment(1)
The object inside the array is still pass by ref where it mutate the original array. You need to deep clone your array. Node 17 and above have out of the box method called structuredClone(). If you're using node version lower than 17, use ungap/structured-clone npm package which does the same thingStoma

© 2022 - 2024 — McMap. All rights reserved.