Copying an array of objects into another array in javascript (Deep Copy)
Asked Answered
O

10

26

Copying an array of objects into another array in javascript using slice(0) and concat() doesnt work.

I have tried the following to test if i get the expected behaviour of deep copy using this. But the original array is also getting modified after i make changes in the copied array.

var tags = [];
for(var i=0; i<3; i++) {
    tags.push({
        sortOrder: i,
        type: 'miss'
    })
}
for(var tag in tags) { 
    if(tags[tag].sortOrder == 1) {
        tags[tag].type = 'done'
    }
}
console.dir(tags)

var copy = tags.slice(0)
console.dir(copy)

copy[0].type = 'test'
console.dir(tags)

var another = tags.concat()
another[0].type = 'miss'
console.dir(tags)

How can i do a deep copy of a array into another, so that the original array is not modified if i make a change in copy array.

Omniscient answered 12/2, 2015 at 16:25 Comment(5)
I'm not sure what you're trying to do but. I suggest changing your second for loop to a for of loop for of(var tag of tags) { if(tag.sortOrder == 1) { tag.type == 'done' }}Busily
Depending on your environment, you might try Object.create?Burgrave
@zlatko can you give an example of the sameOmniscient
Oh, var newObject = Object.create(oldObject) should give you a proto based and dereferenced clone of the old object. Not sure about arrays, buy you can try. The environment part of the comment is that I don't know if you're on V8 or maybe other JS engines, I think it's not supported everywhere (but there are polyfils).Burgrave
Actually it seems it is: kangax.github.io/compat-table/es5/#Object.createBurgrave
S
78

Try

var copy = JSON.parse(JSON.stringify(tags));
Sheltonshelty answered 12/2, 2015 at 16:32 Comment(4)
Over a yeah and a half old, and still helpful !Manley
@Cloudcapped Well, this works because you're serializing the array/object into a string. When you parse that string, entirely new objects are instantiated, as if you received a payload from some api. References are not preserved though, so if you have array elements that point to other elements, this will be dangerous.Bruxelles
@SavaB. Agreed :)Cloudcapped
Keep in mind that it won't work if any of objects (tags) in the array is a circular structure, meaning that it references itself indirectly. That case will end up with "TypeError: Converting circular structure to JSON" error.Antiperistalsis
L
14

Try the following

// Deep copy
var newArray = jQuery.extend(true, [], oldArray);

For more details check this question out What is the most efficient way to deep clone an object in JavaScript?

Louque answered 12/2, 2015 at 16:34 Comment(1)
This doesn't work because the result is an object, not an array.Telex
H
5

As mentioned Here .slice(0) will be effective in cloning the array with primitive type elements. However in your example tags array contains anonymous objects. Hence any changes to these objects in cloned array are reflected in tags array.

@dangh's reply above derefences these element objects and create new ones.

Here is another thread addressing similar situation

Hairdresser answered 12/2, 2015 at 16:48 Comment(0)
Q
4

A nice way to clone an array of objects with ES6 is to use spread syntax:

const clonedArray = [...oldArray];

MDN

Quincentenary answered 27/5, 2018 at 17:44 Comment(1)
This is a shallow copyFanechka
M
1

Easiest and the optimistic way of doing this in one single line is using Underscore/Lodash

let a = _.map(b, _.clone)

Middleman answered 2/11, 2017 at 18:28 Comment(0)
K
1

You just need to use the '...' notation.

// THE FOLLOWING LINE COPIES all elements of 'tags' INTO 'copy'
var copy = [...tags]

When you have an array say x, [...x] creates a new array with all the values of x. Be careful because this notation works slightly differently on objects. It splits the objects into all of its key, value pairs. So if you want to pass all the key value pairs of an object into a function you just need to pass function({...obj})

Kellsie answered 16/12, 2018 at 11:2 Comment(3)
He needs a deep copy, not a shallow copy.Rancher
this won't result in a deep copy, the objects in the new array will still be referencing to the ones in the old arrayApocynthion
Oh, okay. SorryKellsie
B
0

Same issue happen to me. I have data from service and save to another variable. When ever I update my array the copied array also updated. old code is like below

//$scope.MyData get from service
$scope.MyDataOriginal = $scope.MyData;

So when ever I change $scope.MyData also change $scope.MyDataOriginal. I found a solution that angular.copy right code as below

$scope.MyDataOriginal = angular.copy($scope.MyData);
Bufford answered 23/11, 2017 at 12:51 Comment(0)
S
0

I know that this is a bit older post but I had the good fortune to have found a decent way to deep copy arrays, even those containing arrays, and objects, and even objects containing arrays are copied... I only can see one issue with this code is if you don't have enough memory I can see this choking on very large arrays of arrays and objects... But for the most part it should work. The reason that I am posting this here is that it accomplishes the OP request to copy array of objects by value and not by reference... so now with the code (the checks are from SO, the main copy function I wrote myself, not that some one else probably hasn't written before, I am just not aware of them)::

var isArray = function(a){return (!!a) && (a.constructor===Array);}
var isObject = function(a){return (!!a) && (a.constructor===Object);}
Array.prototype.copy = function(){
    var newvals=[],
        self=this;
    for(var i = 0;i < self.length;i++){
        var e=self[i];
        if(isObject(e)){
            var tmp={},
                oKeys=Object.keys(e);
            for(var x = 0;x < oKeys.length;x++){
                var oks=oKeys[x];
                if(isArray(e[oks])){
                    tmp[oks]=e[oks].copy();
                } else { 
                    tmp[oks]=e[oks];
                }
            }
            newvals.push(tmp);
        } else {
            if(isArray(e)){
                newvals.push(e.copy());
            } else {
                newvals.push(e);
            }
        }
    }
    return newvals;
}

This function (Array.prototype.copy) uses recursion to recall it self when an object or array is called returning the values as needed. The process is decently speedy, and does exactly what you would want it to do, it does a deep copy of an array, by value... Tested in chrome, and IE11 and it works in these two browsers.

Standridge answered 7/11, 2018 at 16:30 Comment(0)
A
0

The way to deeply copy an array in JavaScript with JSON.parse:

let orginalArray=
[
 {firstName:"Choton", lastName:"Mohammad", age:26},
 {firstName:"Mohammad", lastName:"Ishaque", age:26}
];

let copyArray = JSON.parse(JSON.stringify(orginalArray));
copyArray[0].age=27;

console.log("copyArray",copyArray);
console.log("orginalArray",orginalArray);
Activist answered 27/6, 2022 at 9:16 Comment(0)
D
-1

For this i use the new ECMAScript 6 Object.assign method :

let oldObject = [1,3,5,"test"];
let newObject = Object.assign({}, oldObject)

the first argument of this method is the array to be updated, we pass an empty object because we want to have a completely new object,

also you can add other objects to be copied too :

let newObject = Object.assign({}, oldObject, o2, o3, ...)
Depreciable answered 23/8, 2017 at 11:13 Comment(1)
even with Object.assign you have same issues, every method that exists right now in Javascript works ok with primitives, if you have your object with keys that have as value another object, references will be keptDervish

© 2022 - 2024 — McMap. All rights reserved.