将 JavaScript 中的数组复制到另一个数组时:
var arr1 = ['a','b','c'];
var arr2 = arr1;
arr2.push('d'); //Now, arr1 = ['a','b','c','d']
我意识到它arr2
指的是与 相同的数组arr1
,而不是一个新的、独立的数组。如何复制数组以获得两个独立的数组?
将 JavaScript 中的数组复制到另一个数组时:
var arr1 = ['a','b','c'];
var arr2 = arr1;
arr2.push('d'); //Now, arr1 = ['a','b','c','d']
我意识到它arr2
指的是与 相同的数组arr1
,而不是一个新的、独立的数组。如何复制数组以获得两个独立的数组?
用这个:
let oldArray = [1, 2, 3, 4, 5];
let newArray = oldArray.slice();
console.log({newArray});
基本上,该slice()
操作会克隆数组并返回对新数组的引用。
对于引用、字符串和数字(而不是实际对象),将slice()
对象引用复制到新数组中。原始数组和新数组都指向同一个对象。如果引用的对象发生更改,则更改对新数组和原始数组都可见。
字符串和数字等原语是不可变的,因此不可能更改字符串或数字。
在 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 () {}];
根据数组中元素的类型,我们可以使用各种技术进行深度复制。
文字值(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)。
文字值数组 (type1) 和文字结构 (type2)
该JSON.parse(JSON.stringify(myArray))
技术可用于深度复制文字值(布尔值、数字、字符串)和文字结构(数组、对象),但不能用于原型对象。
所有数组(type1、type2、type3)
jQuery$.extend(myArray)
技术可用于深度复制所有数组类型。Underscore和Lo-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
不需要 jQuery... 工作示例
var arr2 = arr1.slice()
这将从数组的起始位置复制到数组0
的末尾。
重要的是要注意它对于原始类型(字符串、数字等)将按预期工作,并且还解释了引用类型的预期行为......
如果你有一个引用类型的数组,比如 type Object
。该数组将被复制,但两个数组都将包含对相同Object
's 的引用。因此,在这种情况下,即使实际复制了数组,该数组似乎也是通过引用复制的。
的替代方法slice
是concat
,它可以以两种方式使用。其中第一个可能更具可读性,因为预期行为非常明确:
var array2 = [].concat(array1);
第二种方法是:
var array2 = array1.concat();
Cohen(在评论中)指出后一种方法具有更好的性能。
其工作方式是该concat
方法创建一个新数组,该数组由调用它的对象中的元素组成,后跟作为参数传递给它的任何数组的元素。因此,当没有传递参数时,它只是简单地复制数组。
Lee Penkman 也在评论中指出,如果有机会array1
is undefined
,您可以返回一个空数组,如下所示:
var array2 = [].concat(array1 || []);
或者,对于第二种方法:
var array2 = (array1 || []).concat();
请注意,您也可以使用slice
:执行此操作var array2 = (array1 || []).slice();
。