如何克隆一个包含对象的JavaScript数组?

15

我有一个结果集,它是一个对象数组。我需要克隆它,这样我就可以对其进行更改,而不会影响原始数据。

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.
        }
    });
});
在这个例子中,我创建了一个名为data的变量,并将其设置为我的“源数据”。
我期望能够更改这个新数据变量,但实际上当对其进行更改时,源数据(w2ui.grid.records)也会被更改。
有没有一种正确的方法可以克隆这个集合,以便我可以拥有一个新的数据实例来修改?

使用slice(0)将数组进行克隆。例如:clonedArray = originalArray.slice(0),它将创建一个新的数组。 - Gerardo
可能是如何正确克隆JavaScript对象?的重复问题。 - t.niese
9个回答

35

编辑

深拷贝请使用 JSON.parse(JSON.stringify(arr));

浅拷贝请使用 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);


10
这仍会通过引用传递子对象,因此更改将影响原始对象。 - monners
我尝试了一下,但似乎仍然从源对象中删除(删除属性),而不是克隆的对象。在我的示例中,您可以看到我检查要删除哪些属性。这些属性被从w2ui.grid.records中删除,这是我的核心数据集,需要保持不变。 - SBB
如果您需要进行深度克隆,因为您的数组也包含对象/数组,请尝试使用此方法... https://github.com/pvorb/clone - Rik Lewis
这个深度克隆的例子在这种情况下完美地运行了。谢谢。 - SBB
@SBB 欢迎,但请记住它不适用于具有方法的对象,只适用于简单对象,如JSON对象、普通对象等。 - zer00ne
我的建议是:a.map(x=>x) 可以完美地克隆 a。 - imaginair

14

ES6:

如果您想要克隆对象,您需要使用扩展运算符来克隆数组和对象:

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

感谢ES6的方式来完成它。 - MADPT
9
你不需要展开数组,因为map方法会自动帮你处理: const newArrayOfObjects = originalArrayOfObject.map(i => ({ ...i})); - Art Schmidt
1
请注意,如果您有嵌套数组,则此方法将无法正确工作并创建浅层副本。 - Mario

3

由于您正在使用jQuery,您可以尝试使用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>


3

structuredClone

在JavaScript中,深度复制对象数组的现代方法是使用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}]


终于!喜欢这个。 - Liran H
我很高兴你喜欢我的代码。欢迎。 - XMehdi01

1

1
以下代码对我来说可以深度克隆一个没有任何函数存储的对象数组。
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;
    };

1
这是因为数组被视为指针,所以设置一个新变量只是指向相同的数组。
我所知道的最简单的方法是使用切片...
var data = w2ui.grid.records.slice(0);

这将创建一个包含所有原始值的新数组,因为您从第一个值(0)开始切片。
如果您需要进行深层克隆,因为您的数组也包含对象/数组,请尝试以下方法...

https://github.com/pvorb/clone


0

有多种方法可以做到这一点 -

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);


6
这些方法都无法防止修改原始数据。如果你在其中一份副本中修改某个值,原始值也会改变,因为它们具有相同的引用。 - zero_cool

-1

你可以通过ES6的展开运算符来实现这个功能

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]

相同的语法也可以用于JavaScript对象

var newObj = [...existingObj]


这不是正确的。扩展运算符只复制第一层并创建一个新的引用,但更深层次的值仍然共享同一个引用。 - Samuel Goldenbaum
1
答案对用户来说是误导性的,对于OP的问题也不正确,因为OP的问题是克隆一个对象数组并对其进行更改,而不触及原始数据。 - Samuel Goldenbaum
1
不,@arun,答案不正确。这不是一个观点 - 根据您提出的扩展,修改数组中的对象将更新原始数组。这不是一个观点,事实上这使得答案不正确。请随时测试以进行确认。 - Samuel Goldenbaum
“请随意测试自己”- 您正在寻找更深层次的值(嵌套对象/数组),这就是为什么我说您可以找到更好的解决方案,但这是否是实际问题呢? - Arun Kumar
1
不是更深层嵌套的值。问题标题为:“如何克隆Javascript对象数组?”,然后明确表示“...这是一个对象数组。”您的示例将引用原始数据类型。任何搜索类似于“如何克隆Javascript对象数组”的互联网用户都会找到您的答案-这不是克隆数组对象而不保留引用的正确答案。这已经在其他几个答案中明确指出,因此进一步争论只会被视为防御性的。祝您有愉快的一天,无需继续讨论。 - Samuel Goldenbaum
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接