15

I have a result set which is an array of objects. I need to clone this so I can make changes to it, without touching the original data.

var data = w2ui.grid.records,
exclude = Array('recid', 'w2ui'); // Exclude these data points from the pivot
// Modify our tempData records to remove HTML
$.each(data, function(key, value) {
    $.each(value, function(_key, _value) {
        if(jQuery.inArray(_key, exclude) != -1) {
            delete data[key][_key];
        }else{
            data[key][_key] = $('<div>'+_value+'</div>').text(); // <div></div> for those which are simply strings.
        }
    });
});

In this example, I created a variable called data and set it to my "Source Data".

I expected to be able to make changes to this new data variable but it appears that when making changes to it, the source data is being changed (w2ui.grid.records).

Is there a proper way to clone this set so I can have a new instance of the data to modify?

2
  • use slice(0). Example: clonedArray = originalArray.slice(0) it will create a new array. Commented Mar 1, 2017 at 5:37
  • Possible duplicate of How do I correctly clone a JavaScript object? Commented Mar 1, 2017 at 5:46

9 Answers 9

36

EDIT

Deep clone use JSON.parse(JSON.stringify(arr));

Shallow clone Use slice(0);

var arr = [{'obj1':1}, {'obj2':2}];
var clone = arr.slice(0);
console.log(clone);

var arr = [{'obj1':1}, {'obj2':2}]
var clone = JSON.parse(JSON.stringify(arr));
console.log(clone);

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

6 Comments

This will still pass sub-objects by reference, so mutations will affect the original.
I gave this a shot and it still appears to be removing (deleting the properties) from the source objects instead of the cloned ones. In my example, you can see where I have my check to see which properties I should be removing. Those are getting remove from w2ui.grid.records, my core data set that needs to be left untouched.
If you need a deep clone, because your array contains objects/arrays too, try this... github.com/pvorb/clone
The deep clone example worked perfectly in this situation. Thanks
@SBB you are welcome, but remember it doesn't work on objects with methods, just simple objects like JSON objects, plain objects, etc.
|
14

ES6:

If you want to have cloned objects too, you have to spread array and objects:

const newArrayOfObjects = [
  ...originalArrayOfObject
].map(i => ({ ...i}));

2 Comments

You don't need to spread the array since map does that for you: const newArrayOfObjects = originalArrayOfObject.map(i => ({ ...i}));
please be aware that if you have a nested array this won't work correctly and create shallow copies.
5

structuredClone

The modern way to deep copy an array of objects in JavaScript is to use structuredClone:

const arr1 =[{'obj1':1}, {'obj2':2}];
const arr2 = structuredClone(arr1); //copy arr1
arr2.push({'obj3':3});

console.log(arr1); //[{'obj1':1}, {'obj2':2}]
console.log(arr2); //[{'obj1':1}, {'obj2':2}, {'obj3':3}]

2 Comments

Finally! Love this.
I'm glad you like my code Welcome
3

Since you are using jquery you can try extend:

var arr = [{'obj1':1}, {'obj2':2}];
var clone = jQuery.extend(true, [], arr);
clone[0]['obj1']=10;
console.log(clone);
console.log(arr);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Comments

1

Lodash has a method specifically for this called clonedeep. There's a standalone package for it if you don't want to pull in the entire library:

https://www.npmjs.com/package/lodash.clonedeep

Comments

1

This is because an array is held as a pointer, so setting a new variable just points to the same array.

The easiest way I know of is with slice...

var data = w2ui.grid.records.slice(0);

This creates a new array with all of the original values in, because you're slicing from the first one (0).

If you need a deep clone, because your array contains objects/arrays too, try this...

https://github.com/pvorb/clone

Comments

1

below code worked for me to deep Clone an array of object which does not have any function stored in them.

const deepClone = input => {
        if (typeof input !== 'object') return input;
        const output = Array.isArray(input) ? [] : {};
        const keys = Object.keys(input);
        keys.forEach(key => {
            output[key] = deepClone(input[key]);
        });
        return output;
    };

Comments

0

There are various ways to do it-

let arr = [{
  'obj1': 1
}, {
  'obj2': 2
}];

// 1
const arr2 = arr.slice();
console.log(arr2);

// 2
const arr3 = [].concat(arr);
console.log(arr3);

// 3
// or use the new ES6 Spread
const arr4 = [...arr];
console.log(arr4);

// 4
const arr5 = Array.from(arr);
console.log(arr5);

1 Comment

None of these will prevent mutating the original data. If you mutate a value one of the copies, the original value will also change because they have the same reference.
-1

You can achieve this from ES6 spread operators

var arr1 = [1]
var arr2 = arr1
arr1 === arr2 //true
arr2.push(2)
arr2  //[1, 2]
arr1  //[1, 2]
var arr3 = [...arr1]  //create a copy of existing array
arr1 === arr3  //false
arr2 === arr3  //false
arr3.push(3)
arr3  //[1, 2, 3]
arr1  //[1, 2]
arr2  //[1, 2]

Same syntax can be used for javascripts object as well

var newObj = [...existingObj]

7 Comments

This is not correct. The spread operator only copies the first level with a new reference, but the deeper values are still referenced together.
@SamuelG, I think you are trying to say that my answer was partially correct. Right...
the answer is misleading for users and not correct for the OP's question which was to clone an array of objects and make changes to it, without touching the original data.
No @arun, the answer is not correct. It's not an opinion - modifying objects within an array, as per the spread you suggested, will update the original array. That's not an opinion and does, in fact, make the answer incorrect. Feel free to test yourself for your own confirmation.
No, not deeper nested values. The question is titled: "How to clone a Javascript Array of Objects?" and then specifically says "...which is an array of objects. " Your example would reference primitives. Any internet user who searches something similar to "How to clone a Javascript Array of Objects" would find your answer - which is not a correct answer for cloning an array of objects without maintaining a reference. This has clearly been pointed out in several other answers so arguing further would only be viewed as defensive. Have a great day, no need to continue the thread.
|

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.