在JavaScript中按值复制数组。

[英]Copying array by value in JavaScript


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 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相同的数组,而不是一个新的独立数组。如何复制该数组以得到两个独立的数组?

20 个解决方案

#1


2036  

Use this:

用这个:

var newArray = oldArray.slice();

Basically, the slice() operation clones the array and returns the reference to the new array. Also note that:

基本上,slice()操作克隆了数组并返回对新数组的引用。还要注意:

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.

诸如字符串和数字之类的原语是不可变的,所以对字符串或数字的更改是不可能的。

#2


337  

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)
var booleanLiteral = true;
var numberLiteral = 1;
var stringLiteral = 'true';

// Literal structures (type2)
var arrayLiteral = [];
var objectLiteral = {};

// Prototypes (type3)
var booleanPrototype = new Bool(true);
var numberPrototype = new Number(1);
var stringPrototype = new String('true');
var arrayPrototype = new Array();
var objectPrototype = new Object(); # or "new function () {}"

From these elements we can create three types of arrays.

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

// 1) Array of literal-values (boolean, number, string) 
var type1 = [true, 1, "true"];

// 2) Array of literal-structures (array, object)
var type2 = [[], {}];

// 3) Array of prototype-objects (function)
var 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

  • Array of literal-values (type1)
    The 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 Slice has higher performance than Concat (http://jsperf.com/duplicate-array-slice-vs-concat/3).

    可以使用文本值(布尔值、数字和字符串)来对数组进行深度复制,并使用myArray.slice()和myArray.concat()技术来进行深度复制。其中Slice的性能比Concat更高(http://jsperf.com/double -array-slice- Slice -vs-concat/3)。

  • 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.

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

  • All arrays (type1, type2, type3)
    The jQuery $.extend(myArray) technique can be used to deep-copy all array-types. Libraries like Underscore and Lo-dash offer 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、type2、type3) jQuery $.extend(myArray)技术可以用于深入地复制所有的数组类型。像下划线和Lo-dash这样的库提供了类似于jQuery $.extend()的深度复制函数,但是性能更低。更令人惊讶的是,$.extend()的性能比JSON.parse(JSON.stringify(myArray))技术的性能要高。对于那些避开第三方库(如jQuery)的开发人员,您可以使用以下自定义函数;它的性能高于$。扩展并深入地复制所有数组。

    function copy(o) {
      var output, v, key;
      output = Array.isArray(o) ? [] : {};
      for (key in o) {
        v = o[key];
        output[key] = (typeof v === "object" && v !== null) ? copy(v) : v;
      }
      return output;
    }  
    

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 arr1 is an array of literal values (boolean, number, or string), you can use any deep copy technique discussed above, where slice has the highest performance.

因为arr1是一个文本值数组(boolean、number或string),您可以使用上面讨论的任何深度复制技术,其中slice具有最高的性能。

// Highest performance for deep copying literal values
arr2 = arr1.slice();

// Any of these techniques will deep copy literal values as well,
//   but with lower performance.
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

#3


143  

No jQuery needed... Working Example

不需要jQuery……工作示例

var arr2 = arr1.slice()

This copys the array from the starting position 0 through 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...

需要注意的是,它将按照预期的方式工作(string、number等),并解释引用类型的预期行为…

If you have an array of Reference types, say of type Object. The array will be 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.

如果你有一个数组引用类型,比如说类型对象。数组将被复制,但是这两个数组将包含对同一个对象的引用。在这种情况下,即使数组被复制,数组也会被引用。

#4


115  

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

你可以使用数组扩展…复制数组。

const itemsCopy = [...items];

const itemsCopy =[…项目);

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 browsers but if you need older support use typescript or babel and compile to ES5.

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

More info on spreads

更多信息在传播

#5


65  

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

另一种选择是concat,它可以用两种方式使用。第一个可能是更可读的,因为预期的行为是非常明确的:

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 concat method 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 array1 is undefined, you can return an empty array as follows:

Lee Penkman也在评论中指出,如果array1没有定义,你可以返回空数组如下:

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

#6


35  

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

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

#7


16  

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.

它将工作。

#8


14  

From ES2015,

从ES2015,

var arr2 = [...arr1];

#9


12  

I personally think Array.from is 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);

#10


10  

If you are in an environment of ECMAScript 6, using the Spread Operator you could do it this way:

如果你处在ECMAScript 6的环境中,使用扩展运算符,你可以这样做:

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

console.log(arr1)
console.log(arr2)
<script src="http://www.wzvang.com/snippet/ignore_this_file.js"></script>

#11


9  

Adding to the solution of array.slice(); be aware that if you have multidimensional array sub-arrays will be copied by references. What you can do is to loop and slice() each sub-array individually

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

same things goes to array of objects, they will be copied by reference, you have to copy them manually

同样的东西也会出现在数组中,它们会被引用,你必须手动复制它们。

#12


4  

In my particular case I needed to ensure the array remained intact so this worked for me:

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

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

#13


4  

Make copy of multidimensional array/object:

复制多维数组/对象:

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

Thanks to James Padolsey for this function.

感谢James Padolsey的这个功能。

Source: Here

来源:这里

#14


4  

As we know in Javascript arrays and objects are by reference, but what ways we can do copy the array without changing the original array later one?

正如我们在Javascript数组和对象中所知道的那样,我们可以在不改变原始数组的情况下复制该数组的方法是什么呢?

Here are few ways to do it:

这里有几种方法:

Imagine we have this array in your code:

假设我们有这个数组在你的代码中:

var arr = [1, 2, 3, 4, 5];

1) Looping through the array in a function and return a new array, like this:

1)在函数中循环遍历数组并返回一个新的数组,如下所示:

 function newArr(arr) {
      var i=0, res = [];
      while(i<arr.length){
       res.push(arr[i]);
        i++;
       }
   return res;
 }

2) Using slice method, slice is for slicing part of the array, it will slice some part of your array without touching the original, in the slice, if don't specify the start and end of the array, it will slice the whole array and basically make a full copy of the array, so we can easily say:

2)使用切片方法,片是切片数组的一部分,它将切一些你没有碰原始数组的一部分,切片,如果不指定数组的开始和结束,它将整个数组切片,基本上整个数组的副本,所以我们可以很容易地说:

var arr2 = arr.slice(); // make a copy of the original array

3) Also contact method, this is for merging two array, but we can just specify one of arrays and then this basically make a copy of the values in the new contacted array:

3)还有contact方法,这是用于合并两个数组的,但是我们可以指定一个数组,然后这基本上复制了新的contact数组中的值:

var arr2 = arr.concat();

4) Also stringify and parse method, it's not recommended, but can be an easy way to copy Array and Objects:

4)也不推荐使用stringify和parse方法,但是可以很容易地复制数组和对象:

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

5) Array.from method, this is not widely supported, before use check the support in different browsers:

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

var arr2 = Array.from(arr);

6) ECMA6 way, also not fully supported, but babelJs can help you if you want to transpile:

6)ECMA6路,也不完全支持,但如果你想要转接,babelJs可以帮助你:

let arr2 = [...arr];

#15


2  

If you want to make a new copy of an object or array, you must explicitly copy the properties of the object or the elements of the array, for example:

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

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

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

You can search for more information on Google about immutable primitive values and mutable object references.

您可以在谷歌中搜索关于不可变原始值和可变对象引用的更多信息。

#16


2  

You can also use ES6 spread operator to copy Array

您还可以使用ES6扩展操作符来复制数组。

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

#17


2  

Here are few more way to copy:

这里还有一些复制的方法:

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

#18


1  

Here's a variant:

这里有一个变体:

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
 */

#19


1  

Using jQuery deep copy could be made as following:

使用jQuery deep copy可以进行如下操作:

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

#20


1  

There's the newly introduced Array.from, but unfortunately, as of the time of this writing it's only supported on recent Firefox versions (32 and higher). It can be simply used as follows:

这是新引入的Array.from,但不幸的是,在撰写本文时,它只支持最近的Firefox版本(32和更高版本)。它可以简单地使用如下:

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

Reference: Here

参考:

Or Array.prototype.map may be used with an identity function:

或Array.prototype。地图可与身分功能使用:

function identity(param)
{
    return param;
}

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

Reference: Here

参考:


注意!

本站翻译的文章,版权归属于本站,未经许可禁止转摘,转摘请注明本文地址:https://www.itdaan.com/blog/2011/09/20/beb5c8f3e76643611f4c536467df0921.html



 
粤ICP备14056181号  © 2014-2020 ITdaan.com