按值复制数组

Copy array by value

提问人:Dan 提问时间:9/20/2011 最后编辑:Penny LiuDan 更新时间:7/28/2023 访问量:1247208

问:

将 JavaScript 中的数组复制到另一个数组时:

var arr1 = ['a','b','c'];
var arr2 = arr1;
arr2.push('d');  // Now, arr1 = ['a','b','c','d']

我意识到它指的是与 相同的数组,而不是一个新的独立数组。如何复制数组以获得两个独立的数组?arr2arr1

JavaScript 数组 深拷贝 按值传递

评论

4赞 Pencroff 9/16/2016
看起来目前在 Chrome 53 和 Firefox 48 中,我们的性能和操作以及新的点差运算符要慢得多。查看 perfjs.fnfoslicespliceArray.from
0赞 EscapeNetscape 10/25/2016
jsben.ch/#/wQ9RU <= 此基准测试概述了复制数组的不同方法
0赞 Walle Cyril 5/26/2017
jsperf.com/flat-array-copy
41赞 Hinrich 9/22/2017
现在是 2017 年,所以你可以考虑使用 ES6 的功能:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/......let arr2 = [...arr1];
2赞 71GA 12/16/2019
好吧,当你声明时,你实际上告诉程序在这两种情况下都指向随机存取存储器中的同一个符号链接。当这个符号链接上的值发生变化时,它会影响和......因此,如果您使用扩散算子,程序将创建一个额外的符号链接,指向随机存取存储器中的不同位置,然后您可以独立操作。a = b;aba= [...b];ab

答:

166赞 jondavidjohn 9/20/2011 #1

无需jQuery...工作实例

var arr2 = arr1.slice()

这会将数组从起始位置复制到数组的末尾。0

需要注意的是,对于基元类型(字符串、数字等),它将按预期工作,并且还要解释引用类型的预期行为......

如果您有一个 Reference 类型的数组,例如 类型 。数组将被复制,但两个数组都将包含对相同 's 的引用。因此,在这种情况下,即使数组实际上是复制的,数组似乎也是通过引用复制的。ObjectObject

评论

18赞 jondavidjohn 10/15/2014
不,这不会是一个深度副本。
1赞 pradeep1991singh 12/19/2018
试试这个;var arr2 = JSON.stringify(arr1); arr2 = JSON.parse(arr2);
4赞 Isaac Pak 4/13/2019
这个答案和公认的答案有什么区别?
0赞 Ravi Sharma 12/31/2019
在给定示例的控制台中出现错误“TypeError:window.addEvent 不是函数”
0赞 brc-dd 10/7/2021
@IsaacPak 这是在那之前 2 分钟回答的。
3124赞 Saket 9/20/2011 #2

使用这个:

let oldArray = [1, 2, 3, 4, 5];

let newArray = oldArray.slice();

console.log({newArray});

基本上,slice() 操作克隆数组并返回对新数组的引用。

另请注意:

对于引用、字符串和数字(而不是实际对象),slice() 将对象引用复制到新数组中。原始数组和新数组都引用同一个对象。如果引用的对象发生更改,则这些更改对新数组和原始数组都可见。

字符串和数字等基元是不可变的,因此无法更改字符串或数字。

评论

9赞 Cohen 12/20/2012
关于性能,以下 jsPerf 测试实际上表明 var arr2 = arr1.slice() 和 var arr2 = arr1.concat() 一样快;JSPerf:jsperf.com/copy-array-slice-vs-concat/5jsperf.com/copy-simple-arrayjsperf.com/array-copy/5 的结果让我感到惊讶,以至于我想知道测试代码是否有效。
117赞 Wayne 1/21/2014
尽管这已经获得了大量的赞成票,但它值得另一个,因为它正确地描述了 JS 中的引用,不幸的是,这有点罕见。
38赞 dudewad 2/9/2016
@GáborImre仅仅为了可读性而添加整个库?真?如果我关心可读性,我会添加一条评论。参见:var newArray = oldArray.slice();将 oldArray 克隆到 newArray
13赞 dudewad 2/10/2016
@GáborImre我明白了,当然。但是在我看来,通过包含整个库来回答特定的工程问题是没有帮助的,这是设计臃肿。我看到开发人员经常这样做,然后你最终会得到一个包含整个框架的项目,以取代编写单个函数的必要条件。不过,这只是我的 M.O.。
14赞 crazypeter 2/28/2018
经验教训:不要与 混淆,它为您提供了一个空数组。大不同。.slice().splice()
3赞 Sotiris 9/20/2011 #3

如果要创建对象或数组的新副本,则必须显式复制对象的属性或数组的元素,例如:

var arr1 = ['a','b','c'];
var arr2 = [];

for (var i=0; i < arr1.length; i++) {
   arr2[i] = arr1[i];
}

您可以在 Google 上搜索有关不可变基元值和可变对象引用的更多信息。

评论

1赞 Magne 6/4/2014
您不必显式复制数组对象的属性。请参阅Chtiwi Malek的回答。
77赞 Ninjakannon 10/18/2012 #4

切片的替代方法是 concat,它可以通过 2 种方式使用。其中第一个可能更具可读性,因为预期的行为非常明确:

var array2 = [].concat(array1);

第二种方法是:

var array2 = array1.concat();

Cohen(在评论中)指出,后一种方法具有更好的性能

其工作方式是,该方法创建一个新数组,该数组由调用它的对象中的元素组成,后跟作为参数传递给它的任何数组的元素。因此,当没有传递任何参数时,它只是复制数组。concat

Lee Penkman 也在评论中指出,如果有机会,你可以返回一个空数组,如下所示:array1undefined

var array2 = [].concat(array1 || []);

或者,对于第二种方法:

var array2 = (array1 || []).concat();

请注意,您也可以使用: 执行此操作。slicevar array2 = (array1 || []).slice();

评论

31赞 Cohen 12/20/2012
其实你也可以做: var array2 = array1.concat();在性能方面要快得多。(JSPerf:jsperf.com/copy-simple-arrayjsperf.com/copy-array-slice-vs-concat/5
5赞 lee penkman 8/1/2014
值得注意的是,如果 array1 不是数组,则返回,例如,如果它未定义,你会得到 .我有时会这样做[].concat(array1)[array1][undefined]var array2 = [].concat(array1 || []);
22赞 sarvesh singh 12/13/2012 #5

在处理数字或字符串等简单数据类型时,提到的一些方法效果很好,但是当数组包含其他对象时,这些方法会失败。当我们尝试将任何对象从一个数组传递到另一个数组时,它被作为引用传递,而不是对象。

在 JavaScript 文件中添加以下代码:

Object.prototype.clone = function() {
    var newObj = (this instanceof Array) ? [] : {};
    for (i in this) {
        if (i == 'clone') 
            continue;
        if (this[i] && typeof this[i] == "object") {
            newObj[i] = this[i].clone();
        } 
        else 
            newObj[i] = this[i]
    } return newObj;
};

并简单地使用

var arr1 = ['val_1','val_2','val_3'];
var arr2 = arr1.clone()

它会起作用的。

评论

2赞 sawe 1/22/2013
当我将此代码添加到我的页面“Uncaught RangeError:超出最大调用堆栈大小”时,我收到此错误
1赞 sawe 4/11/2013
很抱歉,如果未声明 arr1,则此错误会在 chrome 中发生。所以我复制粘贴了上面的代码,我得到了错误,但是,如果我声明了数组 arr1,那么我就不会得到错误。您可以通过在 arr2 上方声明 arr1 来改进答案,我看到有很多“我们”没有意识到我们必须声明 arr1(部分原因是当我评估您的答案时,我很匆忙,需要一些“有效”的东西)
0赞 Jason 5/31/2013
.slice()即使数组中有对象,仍然可以正常工作: jsfiddle.net/edelman/k525g
7赞 Samuel 7/8/2013
@Jason,但对象仍然指向同一个对象,因此更改一个对象将更改另一个对象。jsfiddle.net/k525g/1
0赞 themhz 8/12/2013
优秀的代码。我有一个问题,我实际上试图将一个数组复制到另一个数组中,如下所示 var arr1 = new Array() 然后 var arr2 = arr1;如果我在 arr2 中更改某些内容,则更改也会发生在 arr1 上。但是,如果我使用您制作的克隆原型,它实际上会创建该数组的全新实例,或者换句话说,它会复制它。那么这是浏览器问题吗?或者 JavaScript 默认情况下将两个变量设置为一个,当有人执行 var arr2=arr1 时,使用指针指向另一个变量,为什么整数变量不会发生?查看 jsfiddle.net/themhz/HbhtA
9赞 A.Zaben 4/15/2014 #6

添加到array.slice()的解决方案中;请注意,如果您有多维数组,则子数组将被引用复制。 您可以做的是单独循环和切片()每个子数组

var arr = [[1,1,1],[2,2,2],[3,3,3]];
var arr2 = arr.slice();

arr2[0][1] = 55;
console.log(arr2[0][1]);
console.log(arr[0][1]);

function arrCpy(arrSrc, arrDis){
 for(elm in arrSrc){
  arrDis.push(arrSrc[elm].slice());
}
}

var arr3=[];
arrCpy(arr,arr3);

arr3[1][1] = 77;

console.log(arr3[1][1]);
console.log(arr[1][1]);

同样的事情也适用于对象数组,它们将通过引用进行复制,您必须手动复制它们

评论

0赞 Mac 2/16/2017
这个答案值得在页面顶部附近占有一席之地!我正在处理多维子数组,无法理解为什么内部数组总是由 ref 而不是 val 复制。这个简单的逻辑解决了我的问题。如果可能的话,我会给你+100!
85赞 Chtioui Malek 4/23/2014 #7

这是我在尝试了许多方法后的做法:

var newArray = JSON.parse(JSON.stringify(orgArray));

这将创建一个与第一个深层副本无关的新深层副本(不是浅层副本)。

此外,这显然不会克隆事件和函数,但好在您可以在一行中完成,并且它可以用于任何类型的对象(数组、字符串、数字、对象......

评论

6赞 Vladimir Kharlampidi 5/6/2014
这是最好的。我很久以前就使用过同样的方法,并认为老式的递归循环已经没有意义了
2赞 Ruben 6/29/2014
请注意,此选项不能很好地处理类似图的结构:在存在循环时崩溃,并且不保留共享引用。
3赞 Dancrumb 9/19/2014
对于诸如 之类的东西,或者实际上,任何具有原型的东西,这也失败了。此外,s 被转换为 s。Dateundefinednull
10赞 Lawrence Dol 12/10/2014
难道没有人敢于评论序列化为文本然后解析回对象的 CPU 和内存效率严重低下吗?
1赞 wizzwizz4 4/7/2016
这会进行深度复制。这个问题没有问这个。虽然它很有用,但它的作用与其他答案不同。
671赞 tim-montague 5/8/2014 #8

在 Javascript 中,深度复制技术依赖于数组中的元素。让我们从那里开始。

三种类型的元素

元素可以是:文本值、文本结构或原型。

// Literal values (type1)
const booleanLiteral = true;
const numberLiteral = 1;
const stringLiteral = 'true';

// Literal structures (type2)
const arrayLiteral = [];
const objectLiteral = {};

// Prototypes (type3)
const booleanPrototype = new Bool(true);
const numberPrototype = new Number(1);
const stringPrototype = new String('true');
const arrayPrototype = new Array();
const objectPrototype = new Object(); // or `new function () {}

从这些元素中,我们可以创建三种类型的数组。

// 1) Array of literal-values (boolean, number, string) 
const type1 = [ true, 1, "true" ];

// 2) Array of literal-structures (array, object)
const type2 = [ [], {} ];

// 3) Array of prototype-objects (function)
const type3 = [ function () {}, function () {} ];

深度复制技术取决于三种阵列类型

根据数组中元素的类型,我们可以使用各种技术进行深度复制。

深度复制技术

Javascript deep copy techniques by element types

基准

https://www.measurethat.net/Benchmarks/Show/17502/0/deep-copy-comparison

  • 文本值数组 (type1) 、 、 和 技术可用于仅深度复制具有文本值(布尔值、数字和字符串)
    的数组;其中在 Chrome 中具有最高的性能,而 spread 在 Firefox 中具有最高的性能。
    [ ...myArray ]myArray.splice(0)myArray.slice()myArray.concat()slice()...

  • 文本值 (type1) 和文本结构 (type2) 的数组 该技术可用于深度复制文本值(布尔值、数字、字符串)
    和文本结构(数组、对象),但不能深度复制原型对象。
    JSON.parse(JSON.stringify(myArray))

  • 所有数组(type1、type2、type3)

    • structuredClone();
    • Lo-dashjQuery 技术可用于深度复制所有数组类型。Lodash 技术具有最高性能的地方。cloneDeep(myArray)extend(true, [], myArray)cloneDeep()
    • 对于那些避免使用第三方库的人来说,下面的自定义函数将深度复制所有数组类型,性能低于 .cloneDeep()extend(true)
function copy(aObject) {
  // Prevent undefined objects
  // if (!aObject) return aObject;

  let bObject = Array.isArray(aObject) ? [] : {};

  let value;
  for (const key in aObject) {

    // Prevent self-references to parent object
    // if (Object.is(aObject[key], aObject)) continue;
    
    value = aObject[key];

    bObject[key] = (typeof value === "object") ? copy(value) : value;
  }

  return bObject;
}

所以要回答这个问题......

问题

var arr1 = ['a','b','c'];
var arr2 = arr1;

我意识到 arr2 指的是与 arr1 相同的数组,而不是一个新的、独立的数组。如何复制数组以获得两个独立的数组?

由于是文本值(布尔值、数字或字符串)的数组,因此可以使用上面讨论的任何深度复制技术,其中 and spread 具有最高的性能。arr1slice()...

arr2 = arr1.slice();
arr2 = [...arr1];
arr2 = arr1.splice(0);
arr2 = arr1.concat();
arr2 = JSON.parse(JSON.stringify(arr1));
arr2 = structuredClone(arr1);
arr2 = copy(arr1); // Custom function needed, and provided above
arr2 = _.cloneDeep(arr1); // Lo-dash.js needed
arr2 = jQuery.extend(true, [], arr1); // jQuery.js needed

评论

3赞 Dancrumb 9/19/2014
其中许多方法效果不佳。使用 赋值运算符意味着您必须重新赋值 的原始文本值。这种情况非常罕见。使用 obliterates ,所以这根本不是副本。如果数组中的任何值是 Functions 或具有原型(例如 )。arr1splicearr1JSONDate
1赞 helpse 5/14/2015
为什么选择拼接(0)?不应该是slice()吗?我认为它不应该修改原始数组,而拼接会这样做。@JamesMontagne
2赞 tim-montague 5/21/2015
Splice 将创建指向原始数组中元素的指针(浅拷贝)。splice(0) 将为数组中的数字或字符串元素分配新的内存(深拷贝),并为所有其他元素类型(浅拷贝)创建指针。通过将起始值 0 传递给 splice function-method,它不会从原始数组中拼接任何元素,因此不会修改它。
2赞 wizzwizz4 4/7/2016
实际上,只有一种类型的数组:一个“东西”数组。与任何其他数组之间没有区别。[0,"1",{2:3},function random() {return 4;}, [[5,6,7],[8,9,10],[11,12,13]]]
1赞 Jonny 5/16/2022
IMO 这些都具有较差的易读性。有人打算克隆数组的事实对我来说并不明显。称呼它有什么问题?x.clone()
4赞 Brent Keller 5/14/2014 #9

在我的特殊情况下,我需要确保阵列保持完整,所以这对我有用:

// Empty array
arr1.length = 0;
// Add items from source array to target array
for (var i = 0; i < arr2.length; i++) {
    arr1.push(arr2[i]);
}

评论

2赞 unsynchronized 7/1/2014
+1 表示不通过调用执行完全相同操作但以不太明显的方式执行完全相同的函数来向代码添加模糊性。Slice 在引擎盖下可能更有效率,但对于任何从事代码工作的人来说,这显示了您的意图。此外,如果您想(例如)过滤要复制的内容,它可以更轻松地进行优化。请注意,这不会处理深度复制,并且通过引用将相同的内部对象传递到新阵列。这可能是你想做的,也可能不是。
4赞 ink 7/22/2014 #10

复制多维数组/对象:

function deepCopy(obj) {
   if (Object.prototype.toString.call(obj) === '[object Array]') {
      var out = [], i = 0, len = obj.length;
      for ( ; i < len; i++ ) {
         out[i] = arguments.callee(obj[i]);
      }
      return out;
   }
   if (typeof obj === 'object') {
      var out = {}, i;
      for ( i in obj ) {
         out[i] = arguments.callee(obj[i]);
      }
      return out;
   }
   return obj;
}

感谢 James Padolsey 提供此功能。

来源: 这里

12赞 Walter Chapilliquen - wZVanG 7/3/2015 #11

如果您处于 ECMAScript 6 的环境中,则可以使用 Spread Operator,您可以这样做:

var arr1 = ['a','b','c'];
var arr2 = [...arr1]; //copy arr1
arr2.push('d');

console.log(arr1)
console.log(arr2)
<script src="http://www.wzvang.com/snippet/ignore_this_file.js"></script>

219赞 Luke Femur 7/3/2015 #12

您可以使用数组跨差来复制数组。...

const itemsCopy = [...items];

此外,如果要创建一个新数组,并将现有数组作为其中的一部分:

var parts = ['shoulders', 'knees'];
var lyrics = ['head', ...parts, 'and', 'toes'];

现在所有主流浏览器都支持数组扩展,但如果您需要较旧的支持,请使用 typescript 或 babel 并编译为 ES5。

有关点差的更多信息

评论

7赞 SNag 12/29/2019
这不适用于深度复制。 在 JavaScript 中深度克隆数组
1赞 Krisztián Balla 4/19/2022
请注意,这也将在原始数组中为“undefined”创建新条目。这可能会阻止您的代码。
22赞 Boopathi Rajaa 12/24/2015 #13

从 ES2015 开始,

var arr2 = [...arr1];
24赞 Lewis 3/9/2016 #14

我个人认为 Array.from 是一个更具可读性的解决方案。顺便说一句,请注意它的浏览器支持。

// clone
let x = [1, 2, 3];
let y = Array.from(x);
console.log({y});

// deep clone
let clone = arr => Array.from(arr, item => Array.isArray(item) ? clone(item) : item);
x = [1, [], [[]]];
y = clone(x);
console.log({y});

评论

2赞 Banago 7/27/2016
是的,这非常可读。该解决方案完全不直观。谢谢你。.slice()
2赞 Oleksandr Tsurika 1/13/2017 #15

使用jQuery深度复制可以按如下方式进行:

var arr2 = $.extend(true, [], arr1);
5赞 Alireza 3/26/2017 #16

正如我们在 Javascript 中所知道的,数组和对象是通过引用的,但是我们可以通过哪些方法复制数组而不更改原始数组呢?

这里有几种方法可以做到这一点:

想象一下,我们的代码中有这个数组:

var arr = [1, 2, 3, 4, 5];

1)在函数中遍历数组并返回一个新数组,如下所示:

 function newArr(arr) {
      var i=0, res = [];
      while(i<arr.length){
       res.push(arr[i]);
        i++;
       }
   return res;
 }

2)使用slice方法,slice是用于切片数组的一部分,它会在不接触原件的情况下切片你的数组的某些部分,在切片中,如果不指定数组的开始和结束,它会切片整个数组,基本上可以制作一个完整的数组副本,所以我们可以很容易地说:

var arr2 = arr.slice(); // make a copy of the original array

3)还有contact方法,这是为了合并两个数组,但是我们可以只指定其中一个数组,然后这基本上可以复制新联系的数组中的值:

var arr2 = arr.concat();

4)还有stringify和parse方法,不推荐使用,但可以成为复制数组和对象的简单方法:

var arr2 = JSON.parse(JSON.stringify(arr));

5)Array.from方法,这个没有得到广泛的支持,使用前检查不同浏览器的支持情况:

const arr2 = Array.from(arr);

6) ECMA6 方式,也不完全支持,但 babelJs 可以帮到你,如果你想转译:

const arr2 = [...arr];
2赞 ankur kushwaha 7/1/2017 #17

您也可以使用 ES6 扩展算子来复制 Array

var arr=[2,3,4,5];
var copyArr=[...arr];
2赞 ganesh phirke 4/12/2018 #18

以下是几种复制方法:

const array = [1,2,3,4];

const arrayCopy1 = Object.values(array);
const arrayCopy2 = Object.assign([], array);
const arrayCopy3 = array.map(i => i);
const arrayCopy4 = Array.of(...array );

5赞 DragoRaptor 5/18/2018 #19

丹,没必要用花哨的把戏。您需要做的就是通过这样做来复制 arr1。

var arr1 = ['a','b','c'];
var arr2 = [];

var arr2 = new Array(arr1);

arr2.push('d');  // Now, arr2 = [['a','b','c'],'d']

console.log('arr1:');
console.log(arr1);

console.log('arr2:');
console.log(arr2);

// Following did the trick:
var arr3 = [...arr1];
arr3.push('d');  // Now, arr3 = ['a','b','c','d'];

console.log('arr3:');
console.log(arr3);

现在和是存储在不同堆栈中的两个不同的数组变量。在 jsfiddle 上查看此内容。arr1arr2

评论

3赞 Timothy003 11/22/2018
这不会复制数组。它创建一个数组,其中包含一个引用原始元素的元素(即 )。var arr2 = [arr1];
0赞 Jürgen Fink 7/15/2021
@DragoRaptor 我希望你不介意我编辑了你的答案,在这里用你的代码完成了你的片段代码,从jsfiddle中更改为,以便嵌套数组结构能够显示并更好地说明@Timothy003的正确注释。 不过,还是成功了。运行代码片段以查看结果。(输出有点误导,因此我不怪你)。document.write(arr2)console.log(arr2)var arr3 = [...arr1]document.write(arr2)
5赞 BluePie 6/27/2018 #20

您可以将 ES6 与传播 Opeartor 一起使用,它更简单。

arr2 = [...arr1];

有局限性..检查文档传播语法@mozilla

3赞 Willem van der Veen 8/6/2018 #21

当我们想使用赋值运算符 ( ) 复制数组时,它不会创建副本,它只是复制指向数组的指针/引用。例如:=

const oldArr = [1,2,3];

const newArr = oldArr;  // now oldArr points to the same place in memory 

console.log(oldArr === newArr);  // Points to the same place in memory thus is true

const copy = [1,2,3];

console.log(copy === newArr);  // Doesn't point to the same place in memory and thus is false

通常,当我们转换数据时,我们希望保持初始数据结构(例如数组)完好无损。我们通过制作数组的精确副本来做到这一点,这样就可以转换这个数组,而初始数组保持不变。

复制数组的方法:

const oldArr = [1,2,3];

// Uses the spread operator to spread out old values into the new array literal
const newArr1 = [...oldArr];

// Slice with no arguments returns the newly copied Array
const newArr2 = oldArr.slice();

// Map applies the callback to every element in the array and returns a new array
const newArr3 = oldArr.map((el) => el);

// Concat is used to merge arrays and returns a new array. Concat with no args copies an array
const newArr4 = oldArr.concat();

// Object.assign can be used to transfer all the properties into a new array literal
const newArr5 = Object.assign([], oldArr);

// Creating via the Array constructor using the new keyword
const newArr6 = new Array(...oldArr);

// For loop
function clone(base) {
	const newArray = [];
    for(let i= 0; i < base.length; i++) {
	    newArray[i] = base[i];
	}
	return newArray;
}

const newArr7 = clone(oldArr);

console.log(newArr1, newArr2, newArr3, newArr4, newArr5, newArr6, newArr7);

嵌套数组或对象时要小心!

嵌套数组时,将通过引用复制值。以下是这如何导致问题的示例:

let arr1 = [1,2,[1,2,3]]

let arr2 = [...arr1];

arr2[2][0] = 5;  // we change arr2

console.log(arr1);  // arr1 is also changed because the array inside arr1 was copied by reference

因此,当数组中有要复制的对象或数组时,不要使用这些方法。

如果您确实想深度克隆一个 javascript 数组,请与 结合使用,如下所示:JSON.parseJSON.stringify

let arr1 = [1,2,[1,2,3]]

let arr2 = JSON.parse(JSON.stringify(arr1)) ;

arr2[2][0] = 5;

console.log(arr1);  // now I'm not modified because I'm a deep clone

复印性能:

那么我们选择哪一个以获得最佳性能。事实证明,最冗长的方法,循环具有最高的性能。使用循环进行真正的 CPU 密集型复制(大型/多阵列)。forfor

之后,该方法也具有不错的性能,并且也不那么冗长,并且更容易程序员实现。我建议用于日常复制 CPU 密集型数组。此外,如果不需要深度克隆并且性能有问题,请避免使用(大量开销)。.slice().slice()JSON.parse(JSON.stringify(arr))

源性能测试

29赞 ulou 8/22/2018 #22

重要!

这里的大多数答案都适用于特定情况

如果你不关心深层/嵌套的对象和道具使用(ES6):

let clonedArray = [...array]

但是,如果您想进行深度克隆,请改用以下方法:

let cloneArray = JSON.parse(JSON.stringify(array))*

*函数在使用 stringify 时不会被保留(序列化),如果没有它们,您将得到结果。


对于 lodash 用户:

let clonedArray = _.clone(array) 文档

let clonedArray = _.cloneDeep(array) 文档

4赞 abhinav1602 9/26/2018 #23

如果你的数组包含原始数据类型的元素,如int、char或string等,那么你可以使用其中一种方法来返回原始数组的副本,如.slice()或.map()或spread运算符(感谢ES6)。

new_array = old_array.slice()

new_array = old_array.map((elem) => elem)

const new_array = new Array(...old_array);

但是,如果您的数组包含复杂的元素,例如对象(或数组)或更多嵌套对象,那么,您必须确保从顶层到最后一层的所有元素都复制,否则将使用内部对象的引用,这意味着更改object_elements new_array中的值仍将影响old_array。您可以在每个级别上将此复制方法称为创建old_array的深层拷贝

对于深度复制,您可以根据数据类型在每个级别对原始数据类型使用上述方法,也可以使用这种昂贵的方法(如下所述)进行深度复制,而无需做太多工作。

var new_array = JSON.parse(JSON.stringify(old_array));

还有很多其他方法,您可以根据自己的要求使用。我只提到了其中的一些,以便大致了解当我们尝试按值将一个数组复制到另一个数组中时会发生什么。

评论

0赞 albert sh 6/19/2019
非常感谢,您的答案是唯一适用于我的场景的人,
8赞 Nitesh Ranjan 11/18/2018 #24
let a = [1,2,3];

现在,您可以执行以下任一操作来创建数组的副本。

let b = Array.from(a); 

let b = [...a];

let b = new Array(...a); 

let b = a.slice(); 

let b = a.map(e => e);

现在,如果我改变一个,

a.push(5); 

然后,a 是 [1,2,3,5],但 b 仍然是 [1,2,3],因为它有不同的引用。

但我认为,在上面的所有方法中,Array.from 更好,主要是为了复制数组。

评论

1赞 Marc Frame 6/7/2019
哪一个最快?
12赞 DevWL 12/31/2018 #25

基元值始终按其值传递(复制)。但是,复合值是通过引用传递的。

那么我们如何复制这个arr呢?

let arr = [1,2,3,4,5];

在 ES6 中复制阵列

let arrCopy = [...arr]; 

在 ES5 中复制 n 个数组

let arrCopy = arr.slice(); 
let arrCopy = [].concat(arr);

为什么“let arrCopy = arr”不按值传递?

在复合值(如 Object/Array)上将一个变量传递给另一个变量的行为不同。在 copand 值上使用 asign 运算符,我们将引用传递给对象。这就是为什么在删除/添加 arr 元素时两个数组的值都会发生变化的原因。

异常:

arrCopy[1] = 'adding new value this way will unreference';

当您为变量赋值时,您正在更改引用本身,并且它不会影响原始对象/数组。

阅读更多

8赞 Diemauerdk 3/25/2019 #26

我个人更喜欢这种方式:

JSON.parse(JSON.stringify( originalObject ));

评论

0赞 Script47 3/25/2019
那么这里建议的方式呢?
7赞 NimaDoustdar 11/15/2021 #27

当有很多答案时,您必须对这个问题使用最佳实践。

我建议你使用数组点差...复制数组。

var arr1 = ['a','b','c'];

var arr2 = […arr1];

3赞 Eyni Kave 1/15/2022 #28

var arr2 = arr1.slice(0);

这种方式适用于简单的数组

如果你有对象数组这样的复杂数组,那么你必须使用其他解决方案,如:

const arr2 = JSON.parse(JSON.stringify(arr1)); 

例如,我们有一个对象数组,每个单元格在其对象中都有另一个数组字段......在这种情况下,如果我们使用 slice 方法,那么数组字段将通过 Ref 复制,这意味着这些字段更新影响原始数组相同的元素和字段。

8赞 Supercool 9/6/2022 #29

我发现这种方法相对容易:

let arr = [1,2,3,4,5];
let newArr = [...arr];
console.log(newArr);

评论

0赞 Ivar 9/6/2022
已经在这里回答了(还有一堆其他答案)。
3赞 XM01 - stands with Palestine 6/10/2023 #30

结构化克隆

在 JavaScript 中按值复制数组的现代方法是使用 structuredClone

var arr1 = ['a', 'b', 'c'];
var arr2 = structuredClone(arr1); //copy arr1
arr2.push('d');

console.log(arr1); //a,b,c
console.log(arr2); //a,b,c,d