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 } ]
Emile Bergeron
  • 17,074
  • 5
  • 83
  • 129
Stick-With-SQL
  • 213
  • 1
  • 2
  • 6

5 Answers5

22

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; }
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
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;
}); 
Wolfie
  • 1,369
  • 8
  • 16
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));
Roman Yakoviv
  • 1,614
  • 15
  • 19
  • explanation: This successfully strips the reference to original Object when creating the JSON string. Strings are stored by value so it has no reference. – NicoLA Jan 30 '19 at 22:19
  • 1
    This fails with any value that's unsupported in JSON, like Date objects, Functions, etc. See [this answer which explains the downsides](https://stackoverflow.com/a/122704/1218980) – Emile Bergeron Sep 05 '19 at 20:22
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()

jarbaspsf
  • 37
  • 4
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.

  • 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 thing – Standley Peter Mar 24 '23 at 19:31