协慌网

登录 贡献 社区

按值复制数组

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

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

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

答案

用这个:

var newArray = oldArray.slice();

基本上, 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 () {}];

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

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

按元素类型的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 )。

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

  • 所有数组(type1,type2,type3)
    jQuery $.extend(myArray)技术可用于深层复制所有数组类型。像UnderscoreLo-dash这样的库为jQuery $.extend()提供了类似的深拷贝函数,但性能却较低。更令人惊讶的是, $.extend()性能高于JSON.parse(JSON.stringify(myArray))技术http://jsperf.com/js-deep-copy/15
    对于那些回避第三方库(如 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

您可以使用数组传播...来复制数组。

const itemsCopy = [...items];

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

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

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

有关点差的更多信息