按值复制数组


1744

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

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

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


3
它看起来像目前在Chrome 53和Firefox 48,我们有凉爽的性能slicesplice操作和新的传播经营者,并Array.from具有慢得多的实现。看看perfjs.fnfo
Pencroff

jsben.ch/#/wQ9RU <=此基准对复制数组的不同方法进行了概述
EscapeNetscape


对于这个数组(一个包含原始字符串),可以使用var arr2 = arr1.splice();深拷贝,但是这种技术是行不通的,如果你的数组中的元素包含文字结构(即[]{})或原型对象(即function () {}new等)。请参阅下面的答案,以获取更多解决方案。
tfmontague

16
现在是2017年,因此您可以考虑使用ES6功能:let arr2 = [...arr1]; developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…–
Hinrich

Answers:


2700

用这个:

var newArray = oldArray.slice();

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

另请注意:

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

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


9
关于性能,以下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的结果令我感到惊讶,我想知道测试代码是否有效。
科恩

94
尽管这已经获得了很多好评,但值得一提的是,因为它正确地描述了JS中的引用,不幸的是,这种情况很少见。
韦恩

34
@Gábor我只是为了可读性而添加整个库吗?真?如果我担心可读性,我只会添加一条评论。参见:var newArray = oldArray.slice(); //将oldArray复制到newArray
dudewad

12
@GáborImre我明白了。但是我认为通过包含整个库来回答特定的工程问题并没有帮助,这是设计膨胀。我看到开发人员做了很多事情,然后您最终得到一个包含整个框架的项目,以取代必须编写单个函数的情况。不过只是我的MO。
dudewad

5
经验教训:不要.slice()与混淆.splice(),这将为您提供一个空数组。很大的区别。
crazypeter

530

在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深层复制技术

  • 文字值(TYPE1)的阵列
    [...myArray]myArray.splice(0)myArray.slice(),和myArray.concat()技术可以被用于在只文字值(布尔,数字和字符串)深层副本阵列; Spread运算符[...myArray]具有最佳性能的位置(https://measurethat.net/Benchmarks/Show/4281/0/spread-array-performance-vs-slice-splice-concat)。

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

  • 所有数组(type1,type2,type3)
    jQuery $.extend(myArray)技术可用于深度复制所有数组类型。UnderscoreLo-dash等库提供与jQuery 类似的深层复制功能$.extend(),但性能较低。更令人惊讶的是,它$.extend()具有比http://jsperf.com/js-deep-copy/15JSON.parse(JSON.stringify(myArray))技术更高的性能。 对于那些避开第三方库(例如jQuery)的开发人员,您可以使用以下自定义函数;其性能比$ .extend更高,并且可以深度复制所有数组。

function copy(aObject) {
  if (!aObject) {
    return aObject;
  }

  let v;
  let bObject = Array.isArray(aObject) ? [] : {};
  for (const k in aObject) {
    v = aObject[k];
    bObject[k] = (typeof v === "object") ? copy(v) : v;
  }

  return bObject;
}

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

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

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

回答

因为arr1是文字值(布尔值,数字或字符串)的数组,所以可以使用上面讨论的任何深度复制技术,其中散布运算符...的性能最高。

// Highest performance for deep copying literal values
arr2 = [...arr1];

// Any of these techniques will deep copy literal values as well,
//   but with lower performance.
arr2 = arr1.slice();
arr2 = arr1.splice(0);
arr2 = arr1.concat();
arr2 = JSON.parse(JSON.stringify(arr1));
arr2 = $.extend(true, [], arr1); // jQuery.js needed
arr2 = _.extend(arr1); // Underscore.js needed
arr2 = _.cloneDeep(arr1); // Lo-dash.js needed
arr2 = copy(arr1); // Custom-function needed - as provided above

1
这些方法中的许多方法效果都不理想。使用赋值运算符意味着您必须重新分配的原始文字值arr1。这种情况很少见。使用spliceobliterates arr1,因此根本不是副本。JSON如果数组中的任何值为Function或具有原型(例如Date),则使用将失败。
Dancrumb

使用拼接是部分解决方案。在很多情况下,它会比JSON失败。Splice在移动值时会创建字符串和数字的深层副本-从未说过会返回副本。
tfmontague 2014年

1
为什么要拼接(0)?不应该是slice()吗?我认为应该不修改原始数组,而拼接会这样做。@JamesMontagne
helpe 2015年

2
拼接将创建指向原始数组中元素的指针(浅副本)。splice(0)将为数组中的数字或字符串元素分配新的内存(深层副本),并为所有其他元素类型创建指针(浅层副本)。通过将零的起始值传递给拼接函数方法,它将不会拼接原始数组中的任何元素,因此不会对其进行修改。
tfmontague

1
实际上,只有一种类型的数组:“事物”数组。[0,"1",{2:3},function random() {return 4;}, [[5,6,7],[8,9,10],[11,12,13]]]与任何其他阵列之间没有区别。
wizzwizz4 2016年

189

您可以使用阵列跨度...来复制阵列。

const itemsCopy = [...items];

另外,如果要创建一个包含现有数组的新数组,请执行以下操作:

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

现在,所有主要浏览器支持数组扩展,但是如果您需要较早的支持,请使用打字稿或babel并编译为ES5。

有关价差的更多信息


1
这不适用于深复制。用JavaScript深度克隆数组
SNag

151

不需要jQuery ... 工作示例

var arr2 = arr1.slice()

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

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

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


12
不,这不是完整的副本。
jondavidjohn 2014年

尝试这个; var arr2 = JSON.stringify(arr1); arr2 = JSON.parse(arr2);
pradeep1991singh

2
这个答案和接受的答案有什么区别?
艾萨克·朴

在控制台中出现给定示例“ TypeError:window.addEvent不是函数”的错误
Ravi Sharma

72

的替代物slice就是concat,其可以以两种方式来使用。由于预期的行为非常明确,因此第一个可能更易读:

var array2 = [].concat(array1);

第二种方法是:

var array2 = array1.concat();

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

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

李Penkman,也是在评论中指出,如果有一个机会array1undefined,你可以按照如下返回一个空数组:

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

或者,对于第二种方法:

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

需要注意的是,你还可以这样做slicevar array2 = (array1 || []).slice();


31
实际上,您也可以这样做:var array2 = array1.concat(); 性能方面要快得多。(JSPerf:jsperf.com/copy-simple-arrayjsperf.com/copy-array-slice-vs-concat/5
Cohen

5
值得注意的是,如果array1不是数组,则[].concat(array1)返回,[array1]例如,如果未定义,则返回[undefined]。我有时会做var array2 = [].concat(array1 || []);
李·彭克曼

60

在尝试了多种方法之后,我就是这样做的:

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

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

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


4
这是最好的。我用同样的方法在很久以前,认为有在老同学的递归循环没有更多的意义
弗拉基米尔Kharlampidi

1
请注意,此选项不能很好地处理类似图的结构:在存在循环时崩溃,并且不保留共享引用。
鲁宾2014年

1
对于诸如之类的东西Date,或者甚至任何具有原型的东西,这也都会失败。此外,undefineds被转换为nulls。
Dancrumb

7
没有人敢于评论CPU和内存在序列化为文本然后解析回对象方面的效率低下吗?
劳伦斯·多尔

3
该解决方案是唯一可行的解​​决方案。使用slice()确实是一个伪造的解决方案。

20

当使用简单的数据类型(例如数字或字符串)时,上述方法中的某些方法可以很好地工作,但是当数组包含其他对象时,这些方法将失败。当我们尝试将任何对象从一个数组传递到另一个数组时,它将作为引用而不是对象传递。

在您的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
当我将此代码添加到我的页面“ Uncaught RangeError:超出最大调用堆栈大小”时,我收到此错误

1
抱歉,如果未声明arr1,Chrome中会发生此错误。所以我复制粘贴了上面的代码,但是我得到了错误,但是,如果我声明了数组arr1,那么我就没有得到错误。您可以通过在arr2上方声明arr1来改善答案,我看到那里有很多“我们”不认识我们必须声明arr1(部分原因是当我评估您的答案时,我很着急并需要“可以正常使用”的东西)

.slice()即使数组中有对象,仍然可以正常工作:jsfiddle.net/edelman/k525g
Jason

7
@Jason,但是对象仍指向同一对象,因此更改一个将更改另一个。jsfiddle.net/k525g/1
塞缪尔

优秀的代码。我有一个问题,实际上我试图将一个数组复制到另一个数组中,例如var arr1 = new Array(),然后var arr2 = arr1; 如果我在arr2中进行了更改,则arr1也将发生更改。但是,如果我使用您制作的克隆原型,它实际上会创建该数组的完整新实例,或者换句话说,它将对其进行复制。那么这是浏览器问题吗?或javascript默认情况下会在有人使用var arr2 = arr1时使用指针使用指向另一个指向两个变量来设置变量,为什么整数变量不会发生这种情况?参见jsfiddle.net/themhz/HbhtA
themhz 2013年


17

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

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

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

1
是的,这很可读。该.slice()解决方案是完全不直观。谢谢你
Banago

15

重要!

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

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

let clonedArray = [...array]

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

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


对于lodash用户:

let clonedArray = _.clone(array) 文件资料

let clonedArray = _.cloneDeep(array) 文件资料



9

添加到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!
Mac

8

原始值总是通过其值传递(复制)。但是,复合值通过引用传递。

那么我们如何复制此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';

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

阅读更多


6

正如我们在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];

6
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


4

在我的特定情况下,我需要确保阵列保持完整,因此这对我有用:

// 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
+1表示不通过调用功能完全相同的函数(但以不太明显的方式)来增加代码的晦涩感。slice在幕后可能会更高效,但是对任何从事代码工作的人来说,这表明了您的意图。另外,如果您要(例如)过滤要复制的内容,则可以更轻松地进行以后的优化。但是请注意,这不能处理深层复制,并且相同的内部对象将通过引用传递给新数组。这可能是您想要做的,但可能不是。
2014年

4

复制多维数组/对象:

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的这项功能。

资料来源:这里


3

丹,无需花哨的技巧。您需要做的就是通过这样做来复制arr1。

var arr2 = new Array(arr1);

现在arr1arr2是两个不同的数组变量,分别存储在单独的堆栈中。 在jsfiddle上检查一下


这不会复制数组。它创建一个数组,其中包含一个引用原始元素(即var arr2 = [arr1];)的元素。
Timothy003 '18

3

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

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

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

复制数组的方式:

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.parse,请与结合使用JSON.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

复制性能:

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

此后,该.slice()方法也具有不错的性能,并且对于程序员来说也不太冗长和易于实现。我建议.slice()您每天复制不太占用CPU的阵列。JSON.parse(JSON.stringify(arr))如果不需要深度克隆并且性能是一个问题,也请避免使用(很多开销)。

源性能测试


3

如果您的数组包含原始数据类型的元素(例如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 进行DEEP COPY一样在每个级别调用这种复制方法。

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

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

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


非常感谢,您的回答是唯一适合我的情况的人
albert sh

2

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

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

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

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


1
您不必显式复制数组对象的属性。请参阅Chtiwi Malek的答案。
Magne 2014年



2

以下是几种复制方式:

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


2

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

arr2 = [...arr1];

有限制..check docs @mozilla 传播语法


2

快速示例:

  1. 如果数组中的元素是基本类型(字符串,数字等)

var arr1 = ['a','b','c'];
// arr1 and arr2 are independent and primitive elements are stored in 
// different places in the memory
var arr2 = arr1.slice(); 
arr2.push('d');
console.log(arr1); // [ 'a', 'b', 'c' ]
console.log(arr2); // [ 'a', 'b', 'c', 'd' ]

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

var arr1 = [{ x: 'a', y: 'b'}, [1, 2], [3, 4]];
// arr1 and arr2 are independent and reference's/addresses are stored in different
// places in the memory. But those reference's/addresses points to some common place
// in the memory.
var arr2 = arr1.slice(); 
arr2.pop();      // OK - don't affect arr1 bcos only the address in the arr2 is
                 // deleted not the data pointed by that address
arr2[0].x = 'z'; // not OK - affect arr1 bcos changes made in the common area 
                 // pointed by the addresses in both arr1 and arr2
arr2[1][0] = 9;	 // not OK - same above reason

console.log(arr1); // [ { x: 'z', y: 'b' }, [ 9, 2 ], [ 3, 4 ] ]
console.log(arr2); // [ { x: 'z', y: 'b' }, [ 9, 2 ] ]

  1. 2的解决方案:按元素逐个深度复制

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

console.log(arr1); // [ { x: 'a', y: 'b' }, [ 1, 2 ], [ 3, 4 ] ]
console.log(arr2); // [ { x: 'z', y: 'b' }, [ 9, 2 ] ]


1

这是一个变体:

var arr1=['a', 'b', 'c'];
var arr2=eval(arr1.toSource());
arr2.push('d');
console.log('arr1: '+arr1+'\narr2: '+arr2);
/*
 *  arr1: a,b,c
 *  arr2: a,b,c,d
 */

这不是一个坏主意,尽管我最好使用JSON stringify / parse而不是eval,但是再进行一次jsPerf比较将是很不错的选择,而且请注意toSource这不是标准的,例如在Chrome中不起作用。
dmi3y 2014年

1

有新引入的Array.from,但不幸的是,截至撰写本文时,它仅在最新的Firefox版本(32及更高版本)上受支持。可以简单地如下使用:

var arr1 = [1, 2, 3];
console.log(Array.from(arr1)); // Logs: [1, 2, 3]

参考:这里

或者Array.prototype.map可以与身份功能一起使用:

function identity(param)
{
    return param;
}

var arr1 = [1, 2, 3],
    clone = arr1.map(identity);

参考:这里


+1提及Array.from,除Internet Explorer()之外,所有主流浏览器现在都支持+1 。。
mgthomas99

注意Array.from会突变数据,不提供深层复制/深层克隆。
Sudhansu Choudhary

1

对于包含对象的ES6数组

cloneArray(arr) {
    return arr.map(x => ({ ...x }));
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.