ChatGPT解决这个技术问题 Extra ChatGPT

按值复制数组

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

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

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

看起来目前在 Chrome 53 和 Firefox 48 中,slicesplice 操作的性能很酷,而新的传播运算符和 Array.from 的实现速度要慢得多。看perfjs.fnfo
jsben.ch/#/wQ9RU <= 此基准概述了复制数组的不同方法
现在是 2017 年,因此您可以考虑使用 ES6 功能:let arr2 = [...arr1]; developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
好吧,当您声明 a = b; 时,您实际上是在告诉程序在两种情况下都指向随机存取存储器中的相同符号链接。当这个符号链接的值改变时,它会影响 ab...所以如果你使用扩展运算符 a= [...b]; 程序将创建一个额外的符号链接到随机存取存储器中的不同位置,你可以然后独立操作 ab

T
Teocci

用这个:

让 oldArray = [1, 2, 3, 4, 5];让 newArray = oldArray.slice();控制台.log({newArray});

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

另请注意:

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

字符串和数字等原语是不可变的,因此不可能更改字符串或数字。


关于性能,以下 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 的结果让我感到惊讶,以至于我想知道测试代码是否有效。
尽管这已经获得了大量的支持,但它值得另一个,因为它正确地描述了 JS 中的引用,不幸的是,这有点罕见。
@GáborImre 您只是为了便于阅读而添加整个库吗?真的吗?如果我担心可读性,我会添加评论。请参阅: var newArray = oldArray.slice(); //克隆oldArray到newArray
@GáborImre 我明白了,当然。但是在我看来,通过包含整个库来回答特定的工程问题并没有帮助,这是设计膨胀。我看到开发人员经常这样做,然后你最终会得到一个包含整个框架的项目,以取代编写单个函数的过程。不过,只是我的 MO。
经验教训:不要将 .slice().splice() 混淆,后者会给您一个空数组。巨大差距。
t
tim-montague

在 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 () {} ];

深拷贝技术依赖于三种数组类型

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

深拷贝技术

https://i.stack.imgur.com/UL33O.png

基准

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

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

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

所有数组 (type1, type2, type3) Lo-dash cloneDeep(myArray) 或 jQuery extend(true, [], myArray) 技术可用于深度复制所有数组类型。 Lodash cloneDeep() 技术具有最高性能的地方。而对于那些避免使用第三方库的人来说,下面的自定义函数将对所有数组类型进行深度复制,性能低于cloneDeep(),但性能高于extend(true)。

Lo-dash cloneDeep(myArray) 或 jQuery extend(true, [], myArray) 技术可用于深度复制所有数组类型。 Lodash 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 相同的数组,而不是一个新的独立数组。如何复制数组以获得两个独立的数组?

回答

因为 arr1 是文字值数组(布尔值、数字或字符串),您可以使用上面讨论的任何深度复制技术,其中 slice() 和展开 ... 具有最高性能。

arr2 = arr1.slice();
arr2 = [...arr1];
arr2 = arr1.splice(0);
arr2 = arr1.concat();
arr2 = JSON.parse(JSON.stringify(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

这些方法中的许多都不能很好地工作。使用赋值运算符意味着您必须重新分配 arr1 的原始文字值。这是非常罕见的情况。使用 splice 会删除 arr1,因此这根本不是副本。如果数组中的任何值是函数或具有原型(例如 Date),则使用 JSON 将失败。
为什么拼接(0)?不应该是 slice() 吗?我认为它不应该修改原始数组,而 splice 可以。 @JamesMontagne
splice 将创建指向原始数组中元素的指针(浅拷贝)。 splice(0) 将为数组中的数字或字符串元素分配新内存(深拷贝),并为所有其他元素类型创建指针(浅拷贝)。通过将零起始值传递给拼接函数方法,它不会拼接原始数组中的任何元素,因此它不会修改它。
实际上,只有一种类型的数组:“某物”数组。 [0,"1",{2:3},function random() {return 4;}, [[5,6,7],[8,9,10],[11,12,13]]] 与任何其他数组没有区别。
IMO 这些都具有不良的易读性。有人打算克隆数组的事实对我来说并不明显。称它为 x.clone() 有什么问题?
L
Luke Femur

您可以使用数组扩展 ... 来复制数组。

const itemsCopy = [...items];

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

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

数组扩展现在是 supported in all major browsers,但如果您需要较旧的支持,请使用 typescript 或 babel 并编译为 ES5。

More info on spreads


这不适用于深拷贝。 Deep Clone an Array in JavaScript
请注意,这也会在原始数组中为“未定义”创建新条目。这可能会破坏您的代码。
j
jondavidjohn

不需要 jQuery...Working Example

var arr2 = arr1.slice()

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

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

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


不,这不是深拷贝。
尝试这个; var arr2 = JSON.stringify(arr1); arr2 = JSON.parse(arr2);
这个答案和接受的答案有什么区别?
在给定示例的控制台中出现错误“TypeError:window.addEvent 不是函数”
@IsaacPak 这是在此之前 2 分钟回答的。
P
Peter Mortensen

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

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

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

同样,这显然不会克隆事件和函数,但是你可以在一行中完成它的好处,它可以用于任何类型的对象(数组、字符串、数字、对象......)


这是最好的一个。我很久以前使用相同的方法,并认为在老派递归循环中没有更多意义
请注意,此选项不能很好地处理类似图形的结构:存在循环时崩溃,并且不保留共享引用。
对于像 Date 之类的东西,或者实际上,任何具有原型的东西,这也会失败。此外,undefined 被转换为 null
没有人敢于评论序列化为文本然后解析回对象的 CPU 和内存的严重低效吗?
此解决方案是唯一有效的解决方案。使用 slice() 确实是一个虚假的解决方案。
N
Ninjakannon

slice 的替代品是 concat,它有两种使用方式。其中第一个可能更具可读性,因为预期的行为非常清楚:

var array2 = [].concat(array1);

第二种方法是:

var array2 = array1.concat();

Cohen(在评论中)指出后一种方法has better performance

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

Lee Penkman 也在评论中指出,如果 array1 有可能是 undefined,您可以返回一个空数组,如下所示:

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

或者,对于第二种方法:

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

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


其实你也可以这样做: var array2 = array1.concat();它在性能方面要快得多。 (JSPerf:jsperf.com/copy-simple-arrayjsperf.com/copy-array-slice-vs-concat/5
值得注意的是,如果 array1 不是数组,则 [].concat(array1) 返回 [array1],例如,如果它未定义,您将得到 [undefined]。我有时会var array2 = [].concat(array1 || []);
u
ulou

重要的!

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

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

let clonedArray = [...array]

但如果你想进行深度克隆,请改用:

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

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

对于 lodash 用户:

let clonedArray = _.clone(array) documentation

let clonedArray = _.cloneDeep(array) documentation


T
Teocci

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

// 克隆 let x = [1, 2, 3];让 y = Array.from(x);控制台.log({y}); // 深度克隆 let clone = arr => Array.from(arr, item => Array.isArray(item) ? clone(item) : item); x = [1, [], [[]]]; y = 克隆(x);控制台.log({y});


是的,这是非常可读的。 .slice() 解决方案完全不直观。谢谢你。
P
Peter Mortensen

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

在您的 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()

它会起作用的。


当我将此代码添加到我的页面时出现此错误“未捕获 RangeError:超出最大调用堆栈大小”
抱歉,如果未声明 arr1,则 chrome 中会出现此错误。所以我复制粘贴了上面的代码,我得到了错误,但是,如果我声明数组 arr1,那么我没有得到错误。您可以通过在 arr2 上方声明 arr1 来改进答案,我看到有很多“我们”没有认识到我们必须声明 arr1(部分原因是当我评估您的答案时,我很着急并且需要一些“正常工作”的东西)
即使您的数组中有对象,.slice() 仍然可以正常工作:jsfiddle.net/edelman/k525g
@Jason,但对象仍指向同一个对象,因此更改一个对象会更改另一个对象。 jsfiddle.net/k525g/1
优秀的代码。我有一个问题,我实际上尝试将一个数组复制到另一个数组中,例如 var arr1 = new Array() 然后 var arr2 = arr1;如果我在 arr2 中更改某些内容,更改也会发生在 arr1 上。但是,如果我使用您制作的克隆原型,它实际上会创建该数组的一个全新实例,或者换句话说,它会复制它。那么这是浏览器的问题吗?或者 javascript 默认情况下通过一个指向另一个变量来设置两个变量,当有人执行 var arr2=arr1 时,使用指针指向另一个变量,为什么整数变量不会发生?见jsfiddle.net/themhz/HbhtA
B
Boopathi Rajaa

从 ES2015 开始,

var arr2 = [...arr1];

P
Peter Mortensen

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

var arr1 = ['a','b','c']; var arr2 = [...arr1]; //复制 arr1 arr2.push('d'); console.log(arr1) console.log(arr2)


D
DevWL

原始值始终按其值传递(复制)。然而,复合值是通过引用传递的。

那么我们如何复制这个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` 不按值传递?

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

例外:

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

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

read more


A
A.Zaben

添加到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]);

对象数组也是如此,它们将通过引用复制,您必须手动复制它们


这个答案值得放在页面顶部附近!我正在使用多维子数组,无法理解为什么内部数组总是被 ref 而不是 val 复制。这个简单的逻辑解决了我的问题。如果可能的话,我会给你+100!
N
Nitesh Ranjan
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 更好,主要用于复制数组。


哪个最快?
G
GalAbra

我个人更喜欢这种方式:

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

那么建议here的方式?
N
NimaDoustdar

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

我建议您使用数组扩展……来复制数组。

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

var arr2 = […arr1];


A
Alireza

正如我们在 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)还有联系方法,这是用于合并两个数组,但我们可以只指定一个数组,然后这基本上会复制新的联系数组中的值:

var arr2 = arr.concat();

4)还有 stringify 和 parse 方法,不推荐,但可以是复制 Array 和 Objects 的简单方法:

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

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

const arr2 = Array.from(arr);

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

const arr2 = [...arr];

J
Jürgen Fink

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

var arr1 = ['a','b','c']; var arr2 = []; var arr2 = 新数组(arr1); arr2.push('d'); // 现在,arr2 = [['a','b','c'],'d'] console.log('arr1:');控制台.log(arr1); console.log('arr2:');控制台.log(arr2); // 下面是诀窍: var arr3 = [...arr1]; arr3.push('d'); // 现在,arr3 = ['a','b','c','d']; console.log('arr3:');控制台.log(arr3);

现在 arr1arr2 是存储在不同堆栈中的两个不同的数组变量。 Check this out on jsfiddle


这不会复制数组。它创建一个数组,其中一个元素引用原始元素(即var arr2 = [arr1];)。
@DragoRaptor 我希望您不介意我编辑了您的答案,在此处使用 jsfiddle 中的代码完成了您的代码段,将 document.write(arr2) 更改为 console.log(arr2) 以便 nested array 结构显示并更好说明来自@Timothy003 的正确评论。不过,var arr3 = [...arr1] 成功了。运行代码片段以查看结果。 (document.write(arr2) 的输出有点误导,因此我不怪你)。
f
fiat

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

// 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]);
}

+1 通过调用执行完全相同但以不太明显的方式的函数来不为您的代码添加晦涩难懂。 slice 在底层可能更有效,但对于任何处理代码的人来说,这表明了你的意图。另外,如果您想(例如)过滤正在复制的内容,以后可以更轻松地进行优化。但是请注意,这不处理深度复制,并且相同的内部对象通过引用传递给新数组。这可能是您想要做的,也可能不是。
h
heena Jethva

复制多维数组/对象:

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 提供此功能。

来源:Here


a
abhinav1602

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

new_array = old_array.slice()

或者

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

或者

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

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

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

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

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


非常感谢,您的回答是唯一适合我的方案的人,
P
Peter Mortensen

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

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

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

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


您不必显式复制数组对象的属性。请参阅 Chtiwi Malek 的回答。
B
BluePie

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

arr2 = [...arr1];

有限制..检查文档Spread syntax @ mozilla


W
Willem van der Veen

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

常量 oldArr = [1,2,3];常量 newArr = oldArr; // 现在 oldArr 指向内存中的相同位置 console.log(oldArr === newArr); // 指向内存中的同一个地方因此是真的 const copy = [1,2,3]; console.log(复制 === newArr); // 不指向内存中的同一个地方,因此是错误的

通常,当我们转换数据时,我们希望保持初始数据结构(例如数组)完好无损。我们通过制作我们的数组的精确副本来做到这一点,以便可以在原始数组保持不变的情况下对其进行转换。

复制数组的方法:

常量 oldArr = [1,2,3]; // 使用展开运算符将旧值展开到新数组字面量中 const newArr1 = [...oldArr]; // 不带参数的切片返回新复制的数组 const newArr2 = oldArr.slice(); // Map 将回调应用于数组中的每个元素并返回一个新数组 const newArr3 = oldArr.map((el) => el); // concat 用于合并数组并返回一个新数组。没有 args 的 concat 复制一个数组 const newArr4 = oldArr.concat(); // Object.assign 可用于将所有属性转移到一个新的数组字面量中 const newArr5 = Object.assign([], oldArr); // 通过 Array 构造函数使用 new 关键字创建 const newArr6 = new Array(...oldArr); // For 循环函数 clone(base) { const newArray = []; for(let i= 0; i < base.length; i++) { newArray[i] = base[i]; } 返回新数组; } const newArr7 = clone(oldArr); console.log(newArr1, newArr2, newArr3, newArr4, newArr5, newArr6, newArr7);

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

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

让 arr1 = [1,2,[1,2,3]] 让 arr2 = [...arr1]; arr2[2][0] = 5; // 我们改变 arr2 console.log(arr1); // arr1 也改变了,因为 arr1 中的数组是通过引用复制的

因此,当您要复制的数组中存在对象或数组时,请勿使用这些方法。即,仅对基元数组使用这些方法。

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

让 arr1 = [1,2,[1,2,3]] 让 arr2 = JSON.parse(JSON.stringify(arr1)) ; arr2[2][0] = 5;控制台.log(arr1); // 现在我没有被修改,因为我是一个深度克隆

复制性能:

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

之后,.slice() 方法也有不错的性能,而且更简洁,程序员更容易实现。我建议使用 .slice() 来复制 CPU 密集度不高的数组。如果不需要深度克隆并且性能是一个问题,还应避免使用 JSON.parse(JSON.stringify(arr))(大量开销)。

Source performance test


E
Eyni Kave

var arr2 = arr1.slice(0);

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

如果您有类似对象数组的复杂数组,那么您必须使用其他解决方案,例如:

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

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


O
Oleksandr Tsurika

使用 jQuery 深拷贝可以如下进行:

var arr2 = $.extend(true, [], arr1);

a
ankur kushwaha

您还可以使用 ES6 扩展运算符来复制 Array

var arr=[2,3,4,5];
var copyArr=[...arr];

g
ganesh phirke

这里还有一些复制方法:

常量数组 = [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);


a
askilondz

对于包含对象的 ES6 数组

cloneArray(arr) {
    return arr.map(x => ({ ...x }));
}

S
SridharKritha

快速示例:

如果数组中的元素是原始类型(字符串、数字等)

var arr1 = ['a','b','c']; // arr1 和 arr2 是独立的,原始元素存储在 // 内存中的不同位置 var arr2 = arr1.slice(); arr2.push('d');控制台.log(arr1); // [ 'a', 'b', 'c' ] console.log(arr2); // [ 'A B C D' ]

如果数组中的元素是对象字面量,则另一个数组 ({}, [])

var arr1 = [{ x: 'a', y: 'b'}, [1, 2], [3, 4]]; // arr1 和 arr2 是独立的,并且引用/地址存储在内存中的不同位置。但是这些引用/地址指向内存中的某个公共位置//。 var arr2 = arr1.slice(); arr2.pop(); // OK - 不影响 arr1 bcos 只有 arr2 中的地址被删除 // 不是该地址指向的数据 arr2[0].x = 'z'; // 不正常 - 影响 arr1 bcos 在公共区域中所做的更改 // arr1 和 arr2 中的地址指向 arr2[1][0] = 9; // 不行 - 同上原因 console.log(arr1); // [ { x: 'z', y: 'b' }, [ 9, 2 ], [ 3, 4 ] ] console.log(arr2); // [ { x: 'z', y: 'b' }, [ 9, 2 ] ]

解决方案 2:逐元素深度复制

var arr1 = [{ x: 'a', y: 'b'}, [1, 2], [3, 4]]; arr2 = JSON.parse(JSON.stringify(arr1)); arr2.pop(); // OK - 不影响 arr1 arr2[0].x = 'z'; // OK - 不影响 arr1 arr2[1][0] = 9; // OK - 不影响 arr1 console.log(arr1); // [ { x: 'a', y: 'b' }, [ 1, 2 ], [ 3, 4 ] ] console.log(arr2); // [ { x: 'z', y: 'b' }, [ 9, 2 ] ]