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?

Prifulnath
  • 463
  • 7
  • 24
SBB
  • 8,560
  • 30
  • 108
  • 223
  • use `slice(0)`. Example: `clonedArray = originalArray.slice(0)` it will create a new array. – Gerardo Mar 01 '17 at 05:37
  • Possible duplicate of [How do I correctly clone a JavaScript object?](http://stackoverflow.com/questions/728360/how-do-i-correctly-clone-a-javascript-object) – t.niese Mar 01 '17 at 05:46

9 Answers9

35

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);
zer00ne
  • 41,936
  • 6
  • 41
  • 68
  • 10
    This will still pass sub-objects by reference, so mutations will affect the original. – monners Mar 01 '17 at 05:33
  • 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. – SBB Mar 01 '17 at 05:37
  • If you need a deep clone, because your array contains objects/arrays too, try this... https://github.com/pvorb/clone – Rik Lewis Mar 01 '17 at 05:40
  • The deep clone example worked perfectly in this situation. Thanks – SBB Mar 01 '17 at 05:42
  • @SBB you are welcome, but remember it doesn't work on objects with methods, just simple objects like JSON objects, plain objects, etc. – zer00ne Mar 01 '17 at 05:47
  • my best: a.map(x=>x) produces a perfect clone of a – imaginair Jan 24 '18 at 23:03
14

ES6:

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

const newArrayOfObjects = [
  ...originalArrayOfObject
].map(i => ({ ...i}));
Remownz
  • 417
  • 1
  • 4
  • 18
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>
Suchit kumar
  • 11,809
  • 3
  • 22
  • 44
3

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}]
XMehdi01
  • 5,538
  • 2
  • 10
  • 34
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

monners
  • 5,174
  • 2
  • 28
  • 47
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

Rik Lewis
  • 750
  • 4
  • 10
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;
    };
Dharman
  • 30,962
  • 25
  • 85
  • 135
arfath77
  • 31
  • 3
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);
WitVault
  • 23,445
  • 19
  • 103
  • 133
  • 6
    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. – zero_cool Mar 02 '18 at 18:26
-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]

Arun Kumar
  • 323
  • 1
  • 4
  • 15
  • This is not correct. The spread operator only copies the first level with a new reference, but the deeper values are still referenced together. – Samuel Goldenbaum May 07 '20 at 18:56
  • @SamuelG, I think you are trying to say that my answer was partially correct. Right... – Arun Kumar May 12 '20 at 10:40
  • 1
    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. – Samuel Goldenbaum May 12 '20 at 15:06
  • "the answer is misleading" it depends on the reader. You can find better answers it does not mean other answers are incorrect. – Arun Kumar May 12 '20 at 18:40
  • 1
    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. – Samuel Goldenbaum May 12 '20 at 18:51
  • "Feel free to test yourself"- You are looking for deeper values(nested objects/arrays) and that is why I said you can find better solution but is it the actual question ? – Arun Kumar May 12 '20 at 19:21
  • 1
    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. – Samuel Goldenbaum May 12 '20 at 19:49