按值复制数组
当在 JavaScript 中将一个数组复制到另一个数组时:
var arr1 = ['a','b','c'];
var arr2 = arr1;
arr2.push('d'); // Now, arr1 = ['a','b','c','d']
我意识到 arr2 引用与 arr1 相同的数组,而不是一个新的独立数组。如何复制数组以获得两个独立的数组?
When copying an array in JavaScript to another array:
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?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(30)
使用这个:
基本上,
slice()
操作克隆数组并返回对新数组的引用。
另请注意:
对于引用、字符串和数字(而不是实际对象),
slice()
将对象引用复制到新数组中。原始数组和新数组都引用到同一个对象。如果引用的对象发生更改,则新数组和原始数组都可以看到这些更改。字符串和数字等基元是不可变的,因此不可能更改字符串或数字。
Use this:
Basically, the
slice()
operation clones the array and returns a reference to a new array.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.Primitives such as strings and numbers are immutable, so changes to the string or number are impossible.
在 Javascript 中,深度复制技术取决于数组中的元素。让我们从这里开始吧。
三种类型的元素
元素可以是:文字值、文字结构或原型。
从这些元素我们可以创建三种类型的数组。
深度复制技术取决于三种数组类型
根据数组中元素的类型,我们可以使用各种技术进行深度复制。
深度复制技术
基准
https://www.measurethat.net/Benchmarks/Show/17502/0/deep-copy-comparison
文字值数组(type1)
[ ...myArray ]
、myArray.splice(0)
、myArray.slice()
和myArray.concat( )
技术可用于仅深度复制具有文字值(布尔值、数字和字符串)的数组;其中slice()
在 Chrome 中具有最高性能,而 spread...
在 Firefox 中具有最高性能。文字值(type1)和文字结构(type2)数组
JSON.parse(JSON.stringify(myArray)) 技术可用于深度复制文字值(布尔值、数字、字符串)和文字结构(数组、对象),但不能深度复制原型对象。< /p>
所有数组(type1、type2、type3)
structuralClone()
;cloneDeep(myArray)
或 jQueryextend(true, [], myArray)
技术可用于深度复制所有数组类型。其中 LodashcloneDeep()
技术具有最高的性能。cloneDeep()
低,但比extend(true )
。所以回答这个问题...
问题
code
由于
arr1
是一个文字值数组(布尔值、数字或字符串),因此您可以使用上面讨论的任何深度复制技术,其中slice()
和 spread < >... 具有最高的性能。In Javascript, deep-copy techniques depend on the elements in an array. Let's start there.
Three types of elements
Elements can be: literal values, literal structures, or prototypes.
From these elements we can create three types of arrays.
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.
Deep copy techniques
Benchmarks
https://www.measurethat.net/Benchmarks/Show/17502/0/deep-copy-comparison
Array of literal-values (type1)
The
[ ...myArray ]
,myArray.splice(0)
,myArray.slice()
, andmyArray.concat()
techniques can be used to deep copy arrays with literal values (boolean, number, and string) only; whereslice()
has the highest performance in Chrome, and spread...
has the highest performance in Firefox.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)
structuredClone()
;cloneDeep(myArray)
or jQueryextend(true, [], myArray)
techniques can be used to deep-copy all array-types. Where the LodashcloneDeep()
technique has the highest performance.cloneDeep()
and higher performance thanextend(true)
.So to answer the question...
Question
Answer
Because
arr1
is an array of literal values (boolean, number, or string), you can use any deep copy technique discussed above, whereslice()
and spread...
have the highest performance.您可以使用数组扩展
...
来复制数组。const itemsCopy = [...items];
另外,如果想要创建一个新数组并将现有数组作为其中的一部分:
数组扩展现在为 所有主要浏览器均受支持,但如果您需要较旧的支持,请使用 typescript 或 babel并编译为ES5。
有关点差的更多信息
You can use array spreads
...
to copy arrays.const itemsCopy = [...items];
Also if want to create a new array with the existing one being part of it:
Array spreads are now supported in all major browsers but if you need older support use typescript or babel and compile to ES5.
More info on spreads
不需要 jQuery... 工作示例
这将从头开始复制数组将
0
定位到数组末尾。重要的是要注意,它将按原始类型(字符串、数字等)的预期工作,并且还要解释引用类型的预期行为...
如果您有一个引用类型数组,例如
对象
。数组将被复制,但两个数组都将包含对相同对象
的引用。因此,在这种情况下,即使数组实际上已被复制,数组也似乎是通过引用复制的。No jQuery needed... Working Example
This copys the array from the starting position
0
through the end of the array.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 will be copied, but both of the arrays will contain references to the sameObject
's. So in this case it would seem like the array is copied by reference even though the array is actually copied.这就是我在尝试多种方法后所做的:
这将创建一个与第一个副本无关的新深层副本(不是浅副本)。
此外,这显然不会克隆事件和函数,但好处是您可以在一行中完成它,并且它可以用于任何类型的对象(数组、字符串、数字、对象...)
This is how I've done it after trying many approaches:
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 ...)
slice
的替代方案 是concat
,有两种使用方式。第一个方法可能更具可读性,因为预期的行为非常明确:第二种方法是:
Cohen(在评论中)指出后一种方法 具有更好的性能。
其工作方式是,
concat
方法创建一个新数组,该数组由调用它的对象中的元素组成,后跟作为参数传递给它的任何数组的元素。因此,当没有传递参数时,它只是复制数组。Lee Penkman也在评论中指出,如果
array1
有可能未定义
,您可以返回一个空数组,如下所示:或者,对于第二种方法:
注意您也可以使用
slice
执行此操作:var array2 = (array1 || []).slice();
。An alternative to
slice
isconcat
, which can be used in 2 ways. The first of these is perhaps more readable as the intended behaviour is very clear:The second method is:
Cohen (in the comments) pointed out that this latter method has better performance.
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.Lee Penkman, also in the comments, points out that if there's a chance
array1
isundefined
, you can return an empty array as follows:Or, for the second method:
Note that you can also do this with
slice
:var array2 = (array1 || []).slice();
.重要!
这里的大多数答案都适用于特定情况。
如果你不关心深层/嵌套对象和道具使用(ES6):
let clonedArray = [...array]
但如果你想进行深度克隆使用而是:
let cloneArray = JSON.parse(JSON.stringify(array))
**使用 stringify 时,函数不会被保留(序列化),没有它们,您将得到结果。
对于lodash用户:
let clonedArray = _.clone(array)
文档和
let clonedArray = _.cloneDeep(array)
文档Important!
Most of answers here works for particular cases.
If you don't care about deep/nested objects and props use (ES6):
let clonedArray = [...array]
but if you want to do deep clone use this instead:
let cloneArray = JSON.parse(JSON.stringify(array))
**functions won't be preserved (serialized) while using stringify, you will get result without them.
For lodash users:
let clonedArray = _.clone(array)
documentationand
let clonedArray = _.cloneDeep(array)
documentation我个人认为 Array.from 是更具可读性的解决方案。顺便说一下,请注意其浏览器支持。
I personally think Array.from is a more readable solution. By the way, just beware of its browser support.
上面提到的一些方法在处理数字或字符串等简单数据类型时效果很好,但当数组包含其他对象时,这些方法就会失败。当我们尝试将任何对象从一个数组传递到另一个数组时,它将作为引用而不是对象传递。
在您的 JavaScript 文件中添加以下代码:
只需使用
它即可工作。
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:
And simply use
It will work.
从ES2015开始,
From ES2015,
如果您处于 ECMAScript 6 环境中,请使用 Spread 运算符 你可以这样做是这样的:
If you are in an environment of ECMAScript 6, using the Spread Operator you could do it this way:
原始值始终通过其值传递(复制)。然而,复合值是通过引用传递的。
那么我们如何复制这个arr呢?
在 ES6 中复制数组
在 ES5 中复制 n 数组
为什么 `let arrCopy = arr` 不是按值传递?
在复合值(例如对象/数组)上将一个变量传递给另一个变量的行为有所不同。对 copand 值使用 asign 运算符,我们传递对对象的引用。这就是为什么在删除/添加 arr 元素时两个数组的值都会发生变化的原因。
例外:
当您为变量分配新值时,您正在更改引用本身,并且不会影响原始对象/数组。
了解更多
Primitive values are always pass by its value (copied). Compound values however are passed by reference.
So how do we copy this arr?
Copy an Array in ES6
Copy n Array in ES5
Why `let arrCopy = arr` is not passing by value?
Passing one varible to another on Compound values such as Object/Array behave difrently. Using asign operator on copand values we pass reference to an object. This is why the value of both arrays are changing when removing/adding arr elements.
Exceptions:
When you assign a new value to the variable, you are changing the reference itself and it doesn’t affect the original Object/Array.
read more
添加到 array.slice(); 的解决方案请注意,如果您有多维数组,子数组将通过引用复制。
你可以做的是循环和切片()每个子数组单独
相同的东西进入对象数组,它们将通过引用复制,你必须手动复制它们
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
same things goes to array of objects, they will be copied by reference, you have to copy them manually
现在您可以执行以下任一操作来制作数组的副本。
OR
OR
OR OR
OR
现在,如果我改变 a,
那么 a 是 [1,2,3,5] 但 b 仍然是 [1,2,3],因为它有不同的引用。
但我认为,在上述所有方法中 Array.from 更好,主要用于复制数组。
Now you can do any one of the following to make a copy of an array.
OR
OR
OR
OR
Now, if i change a,
Then, a is [1,2,3,5] but b is still [1,2,3] as it has different reference.
But i think, in all the methods above Array.from is better and made mainly to copy an array.
我个人更喜欢这种方式:
I would personally prefer this way:
我发现这个方法比较简单:
I found this method comparatively easier:
当有很多答案时,您必须使用最佳实践来解决此问题。
我建议您使用数组扩展...来复制数组。
var arr1 = ['a','b','c'];
var arr2 = [...arr1];
You must use best practice for this question when there are a lot of answers.
I recommend to you use array spreads … to copy arrays.
var arr1 = ['a','b','c'];
var arr2 = […arr1];
正如我们所知,在 Javascript 中数组和对象是通过引用来实现的,但是我们可以通过什么方式来复制数组而不更改原始数组呢?
这里有几种方法:
想象一下我们的代码中有这个数组:
1)在函数中循环遍历数组并返回一个新数组,如下所示:
2)使用切片方法,切片用于切片数组的一部分,它将对数组的某些部分进行切片,而不触及原始数组,在切片中,如果不指定数组的开始和结束,它将对整个数组进行切片并基本上制作数组的完整副本,因此我们可以轻松地说:
3)还有联系方式,这是用于合并两个数组,但我们可以只指定其中一个数组,然后这基本上会复制新接触的数组中的值:
4)还有 stringify 和 parse 方法,不推荐,但可以是复制数组的简单方法和 Objects:
5) Array.from 方法,这个没有被广泛支持,使用前检查不同浏览器的支持:
6) ECMA6 方式,也没有完全支持,但是如果你想转译,babelJs 可以帮助你:
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?
Here are few ways to do it:
Imagine we have this array in your code:
1) Looping through the array in a function and return a new array, like this:
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:
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:
4) Also stringify and parse method, it's not recommended, but can be an easy way to copy Array and Objects:
5) Array.from method, this is not widely supported, before use check the support in different browsers:
6) ECMA6 way, also not fully supported, but babelJs can help you if you want to transpile:
您可以将 ES6 与扩展 Opeartor 一起使用,它更简单。
有限制..检查文档传播语法@ mozilla
You could use ES6 with spread Opeartor, its simpler.
There are limitations..check docs Spread syntax @ mozilla
丹,没必要用什么花招。您所需要做的就是通过执行此操作来复制 arr1 。
现在,arr1 和 arr2 是两个不同的数组变量,存储在单独的堆栈中。
在 jsfiddle 上查看。
Dan, no need to use fancy tricks. All you need to do is make copy of arr1 by doing this.
Now
arr1
andarr2
are two different array variables stored in separate stacks.Check this out on jsfiddle.
这样仅适用于简单数组。
如果您有复杂数组,例如对象数组,那么您必须使用其他解决方案,例如:
例如,我们有一个对象数组,每个单元格在其对象中有另一个数组字段...在这种情况下,如果我们使用slice方法,那么数组字段将通过Ref复制 这意味着这些字段更新将影响原始数组的相同元素和字段。
This way just work for simple Arrays.
If you have Complex Array like array of Objects then you must use another solutions like:
For example, we have an array of objects that each cell have another array field in its object ... in this situation if we use slice method then the array fields will copy by Ref and that's mean these fields updates will affect on orginal array same element and fields.
StructuredClone
在 JavaScript 中按值复制数组的现代方法是使用
结构化克隆
:structuredClone
The modern way to copy array by value in JavaScript is to use
structuredClone
:在我的特殊情况下,我需要确保阵列保持完整,所以这对我有用:
In my particular case I needed to ensure the array remained intact so this worked for me:
复制多维数组/对象:
感谢 James Padolsey 提供此功能。
来源:此处
Make copy of multidimensional array/object:
Thanks to James Padolsey for this function.
Source: Here
如果您的数组包含原始数据类型的元素,例如int、char或string等,那么您可以使用返回原始数组副本的这些方法之一,例如作为 .slice() 或 .map() 或扩展运算符(感谢 ES6)。
或
或
但是如果您的数组包含复杂元素,例如对象(或数组)或更多嵌套对象,那么,您必须确保您正在复制从顶层到最后一层的所有元素,否则将使用内部对象的引用,这意味着更改 new_array 中的 object_elements 中的值仍然会影响 old_array 。您可以将这种在每个级别进行复制的方法称为深度复制
old_array 的。
对于深复制,您可以根据数据类型在每个级别对原始数据类型使用上述方法,或者您可以使用这种昂贵的方法(下面提到)来进行深复制,而无需执行很多工作。
还有很多其他方法,您可以根据自己的要求使用。我只提到了其中的一些内容,以便让我们大致了解当我们尝试按值将一个数组复制到另一个数组时会发生什么。
If your array contains elements of the primitive data type such as int, char, or string etc then you can user one of those methods which returns a copy of the original array such as .slice() or .map() or spread operator(thanks to ES6).
or
or
BUT if your array contains complex elements such as objects(or arrays) or more nested objects, then, you will have to make sure that you are making a copy of all the elements from the top level to the last level else reference of the inner objects will be used and that means changing values in object_elements in new_array will still affect the old_array. You can call this method of copying at each level as making a DEEP COPY
of the old_array.
For deep copying, you can use the above-mentioned methods for primitive data types at each level depending upon the type of data or you can use this costly method(mentioned below) for making a deep copy without doing much work.
There are a lot of other methods out there which you can use depending on your requirements. I have mentioned only some of those for giving a general idea of what happens when we try to copy an array into the other by value.
如果要创建对象或数组的新副本,则必须显式复制该对象的属性或数组的元素,例如:
您可以在 Google 上搜索有关不可变原始值和可变对象引用的更多信息。
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:
You can search for more information on Google about immutable primitive values and mutable object references.
当我们想要使用赋值运算符(
=
)复制数组时,它不会创建副本,它只是复制指向数组的指针/引用。例如:通常,当我们转换数据时,我们希望保持初始数据结构(例如数组)完整。我们通过制作数组的精确副本来做到这一点,这样就可以在第一个数组保持不变的情况下对其进行转换。
复制数组的方法:
嵌套数组或对象时要小心!:
当嵌套数组时,值将通过引用复制。以下是这可能如何导致问题的示例:
因此,当您要复制的数组中有对象或数组时,请勿使用这些方法。即仅对基元数组使用这些方法。
如果您确实想深度克隆 javascript 数组,请结合使用
JSON.parse
和JSON.stringify
,如下所示:复印性能:
那么我们应该选择哪一种才能获得最佳性能。事实证明,最详细的方法,for 循环具有最高的性能。使用
for
循环进行真正的 CPU 密集型复制(大型/多个数组)。之后,
.slice()
方法也具有不错的性能,并且更简洁,更容易程序员实现。我建议使用.slice()
来日常复制对 CPU 要求不高的数组。如果不需要深度克隆并且性能是一个问题,还要避免使用 JSON.parse(JSON.stringify(arr)) (大量开销)。源性能测试
When we want to copy an array using the assignment operator (
=
) it doesn't create a copy it merely copies the pointer/reference to the array. For example:Often when we transform data we want to keep our initial datastructure (e.g. Array) intact. We do this by making a exact copy of our array so this one can be transformed while the initial one stays intact.
Ways of copying an array:
Be careful when arrays or objects are nested!:
When arrays are nested the values are copied by reference. Here is an example of how this could lead to issues:
So don't use these methods when there are objects or arrays inside your array you want to copy. i.e. Use these methods on arrays of primitives only.
If you do want to deepclone a javascript array use
JSON.parse
in conjunction withJSON.stringify
, like this:Performance of copying:
So which one do we choose for optimal performance. It turns out that the most verbose method, the
for
loop has the highest performance. Use thefor
loop for really CPU intensive copying (large/many arrays).After that the
.slice()
method also has decent performance and is also less verbose and easier for the programmer to implement. I suggest to use.slice()
for your everyday copying of arrays which aren't very CPU intensive. Also avoid using theJSON.parse(JSON.stringify(arr))
(lots of overhead) if no deep clone is required and performance is an issue.Source performance test
使用 jQuery 深层复制可以如下进行:
Using jQuery deep copy could be made as following:
您还可以使用 ES6 扩展运算符来复制数组
You can also use ES6 spread operator to copy Array
这里还有几种复制方法:
Here are few more way to copy: