Javascript 按值复制数组

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7486085/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 02:27:41  来源:igfitidea点击:

Copy array by value

javascriptarrays

提问by Dan

When copying an array in JavaScript to another array:

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

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

I realized that arr2refers to the same array as arr1, rather than a new, independent array. How can I copy the array to get two independent arrays?

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

回答by Saket

Use this:

用这个:

var newArray = oldArray.slice();

Basically, the slice()operation clones the array and returns a reference to a new array.

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

Also note that:

另请注意:

For references, strings and numbers (and not the actual object), slice()copies object references into the new array.Both the original and new array refer to the same object. If a referenced object changes, the changes are visible to both the new and original arrays.

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

Primitives such as strings and numbers are immutable, so changes to the string or number are impossible.

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

回答by tfmontague

In Javascript, deep-copy techniques depend on the elements in an array. Let's start there.

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

Three types of elements

三种元素

Elements can be: literal values, literal structures, or prototypes.

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

// 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 () {}`

From these elements we can create three types of arrays.

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

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

Deep copy techniques depend on the three array types

深拷贝技术取决于三种数组类型

Based on the types of elements in the array, we can use various techniques to deep copy.

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

Javascript deep copy techniques by element types

按元素类型划分的 Javascript 深度复制技术

  • Array of literal-values (type1)
    The [...myArray], myArray.splice(0), myArray.slice(), and myArray.concat()techniques can be used to deep copy arrays with literal values (boolean, number, and string) only; where the Spread operator [...myArray]has the best performance (https://measurethat.net/Benchmarks/Show/4281/0/spread-array-performance-vs-slice-splice-concat).

  • Array of literal-values (type1) and literal-structures (type2)
    The JSON.parse(JSON.stringify(myArray))technique can be used to deep copy literal values (boolean, number, string) and literal structures (array, object), but not prototype objects.

  • All arrays (type1, type2, type3)
    The jQuery $.extend(myArray)technique can be used to deep-copy all array-types. Libraries like Underscoreand Lo-dashoffer similar deep-copy functions to jQuery$.extend(), yet have lower performance. More surprisingly, $.extend()has higher performance than the JSON.parse(JSON.stringify(myArray))technique http://jsperf.com/js-deep-copy/15.
    And for those developers that shy away from third-party libraries (like jQuery), you can use the following custom function; which has higher performance than $.extend, and deep-copies all arrays.

  • 文字值(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()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;
}

So to answer the question...

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

Question

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

I realized that arr2 refers to the same array as arr1, rather than a new, independent array. How can I copy the array to get two independent arrays?

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

Answer

回答

Because arr1is an array of literal values (boolean, number, or string), you can use any deep copy technique discussed above, where the spread operator ...has the highest performance.

因为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

回答by Luke Femur

You can use array spreads ...to copy arrays.

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

const itemsCopy = [...items];

const itemsCopy = [...items];

Also if want to create a new array with the existing one being part of it:

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

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

Array spreads are now supported in all major browsersbut if you need older support use typescript or babel and compile to ES5.

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

More info on spreads

有关点差的更多信息

回答by jondavidjohn

No jQuery needed... Working Example

不需要 jQuery... 工作示例

var arr2 = arr1.slice()

This copys the array from the starting position 0through the end of the array.

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

It is important to note that it will work as expected for primitive types (string, number, etc.), and to also explain the expected behavior for reference types...

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

If you have an array of Reference types, say of type Object. The array willbe copied, but both of the arrays will contain references to the same Object's. So in this case it would seem like the array is copied by reference even though the array is actually copied.

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

回答by Ninjakannon

An alternative to sliceis concat, which can be used in 2 ways. The first of these is perhaps more readable as the intended behaviour is very clear:

的替代方法sliceconcat,它可以以两种方式使用。其中第一个可能更具可读性,因为预期行为非常明确:

var array2 = [].concat(array1);

The second method is:

第二种方法是:

var array2 = array1.concat();

Cohen (in the comments) pointed out that this latter method has better performance.

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

The way this works is that the concatmethod creates a new array consisting of the elements in the object on which it is called followed by the elements of any arrays passed to it as arguments. So when no arguments are passed, it simply copies the array.

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

Lee Penkman, also in the comments, points out that if there's a chance array1is undefined, you can return an empty array as follows:

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

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

Or, for the second method:

或者,对于第二种方法:

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

Note that you can also do this with slice: var array2 = (array1 || []).slice();.

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

回答by Chtiwi Malek

This is how I've done it after trying many approaches:

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

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

This will create a new deep copy not related to the first one (not a shallow copy).

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

Also this obviously will not clone events and functions, but the good thing you can do it in one line, and it can be used for any kind of object (arrays, strings, numbers, objects ...)

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

回答by sarvesh singh

Some of mentioned methods work well when working with simple data types like number or string, but when the array contains other objects these methods fail. When we try to pass any object from one array to another it is passed as a reference, not the object.

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

Add the following code in your JavaScript file:

在您的 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;
};

And simply use

并简单地使用

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

It will work.

它会起作用。

回答by Boopathi Rajaa

From ES2015,

从 ES2015 开始,

var arr2 = [...arr1];

回答by Lewis

I personally think Array.fromis a more readable solution. By the way, just beware of its browser support.

我个人认为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);

回答by ulou

Important!

重要的!

Most of answers here works for particular cases.

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

If you don't care about deep/nested objects and props use (ES6):

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

let clonedArray = [...array]

let clonedArray = [...array]

but if you want to do deep clone use this instead:

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

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

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



For lodash users:

对于 lodash 用户:

let clonedArray = _.clone(array)documentation

let clonedArray = _.clone(array)文件

and

let clonedArray = _.cloneDeep(array)documentation

let clonedArray = _.cloneDeep(array)文件