在javascript中将对象数组复制到另一个数组中

时间:2013-04-26 09:20:28

标签: javascript arrays deep-copy

如何将数组的每个元素(元素都是对象)复制到另一个数组中,以便它们完全独立?我不想更改一个数组中的元素来影响另一个元素。

7 个答案:

答案 0 :(得分:90)

如果目标阵列尚不存在......

...您可以使用slice()concat()slice()可能更具惯用性(您还会看到slice(0),但默认值为0,所以......):

var destinationArray = sourceArray.slice(); // Probably more idiomatic
// or
var destinationArray = sourceArray.concat();

从ES2015(又名ES6)开始,还有Array.from,它可以从任何类似数组的事物(包括实际数组)中创建一个新数组:

var destinationArray = Array.from(sourceArray);

Array.from可以为较旧的JavaScript引擎进行填充/填充。)

从ES2015开始,您可以使用可迭代的扩展表示法和任何可迭代的数组文字(包括数组):

var destinationArray = [...sourceArray];

之后,两个阵列都将具有相同的内容。更改一个阵列不会改变另一个阵列。当然,如果数组条目是一个对象,则两个数组中该对象的条目将指向同一个对象;这不是一个“深层”的副本。

如果目标数组存在...

...并且您想要将源数组的内容附加到它,您可以使用push

destinationArray.push.apply(destinationArray, sourceArray);

通过使用JavaScript函数的push功能调用目标数组上的apply,可以将函数调用的参数指定为数组。 push将推送尽可能多的元素,因此最终会将元素从源数组复制到目标数组。

在ES2015及更高版本中,您可以使用可迭代扩展表示法(...)来制作更清晰的内容:

destinationArray.push(...sourceArray);

请注意,在这两种情况下,调用受限于JavaScript引擎的最大函数参数数量(截至本文撰写时,对于所有主要引擎至少有数千个引用[并且不是数十万个,至少不是对于Chrome的V8])。

这是ES5版本:

var source1, dest1, source2, dest2;

snippet.log("If dest doesn't exist yet:");
source1 = [1, 2, 3, 4];
dest1 = source1.slice(0);
snippet.log("[before change] source1 = " + source1.join(", "));
snippet.log("[before change] dest1 = " + dest1.join(", "));
source1[2] = "three";
dest1[3] = "four";
snippet.log("[after change] source1 = " + source1.join(", "));
snippet.log("[after change] dest1 = " + dest1.join(", "));

snippet.log("If dest already exists and we're just appending:");
source2 = [1, 2, 3, 4];
dest2 = ['a', 'b', 'c', 'd'];
snippet.log("[before append] source2 = " + source2.join(", "));
snippet.log("[before append] dest2 = " + dest2.join(", "));
dest2.push.apply(dest2, source2);
snippet.log("[before change] source2 = " + source2.join(", "));
snippet.log("[before change] dest2 = " + dest2.join(", "));
source2[2] = "three";
dest2[7] = "four";
snippet.log("[after change] source2 = " + source2.join(", "));
snippet.log("[after change] dest2 = " + dest2.join(", "));
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="//tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

答案 1 :(得分:21)

使用此方法的简便方法是:

var cloneArray = JSON.parse(JSON.stringify(originalArray));

我在让arr.concat()arr.splice(0)提供深层副本时遇到问题。上面的片段工作得很好。

答案 2 :(得分:4)

克隆数组的一个好方法是使用数组文字传播运算符。这可以通过 ES2015 来实现。

let objArray = [{name:'first'}, {name:'second'}, {name:'third'}, {name:'fourth'}];

let clonedArr = [...objArray];

console.log(clonedArr) // [Object, Object, Object, Object]

您可以在MDN的传播运算符 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator#Copy_an_array

文档中找到此复制选项

这也是 Airbnb 的最佳做法。 https://github.com/airbnb/javascript#es6-array-spreads

注意:通常情况下,ES2015中的扩展运算符在复制数组时会变深一级。因此,它们不适合复制多维数组。

答案 3 :(得分:3)

var clonedArray = array.concat();

答案 4 :(得分:1)

如果您想继续参考:

import Foundation protocol Mappable { func doSomething() } class User: Mappable { func doSomething() { } } class Value<T: Mappable>: Mappable { var data: T? func doSomething() { } } class Response<T> { var value: T? } func handleResponse< T:Value<User>>(response:Response<T>, completeHandler: (User?, NSError?)->()) { completeHandler(response.value!.data, nil) } let response = Response<Value<User>>() response.value = Value<User>() response.value?.data = User() handleResponse(response, completeHandler:{(r,e) in print(r) })

答案 5 :(得分:1)

有两个重要的注释。

  1. 使用array.concat()无法使用Angular 1.4.4和jQuery 3.2.1(这是我的环境)。
  2. array.slice(0)是一个对象。因此,如果您执行newArray1 = oldArray.slice(0); newArray2 = oldArray.slice(0)之类的操作,则两个新数组将仅引用一个数组,而更改一个数组将影响另一个数组。
  3. 或者,使用newArray1 = JSON.parse(JSON.stringify(old array))只会复制值,因此每次都会创建一个新数组。

答案 6 :(得分:0)

如果您使用的是nodeJS,我建议使用concat()。在所有其他情况下,我发现slice(0)工作正常。