Array nach Wert kopieren


1745

Beim Kopieren eines Arrays in JavaScript in ein anderes Array:

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

Mir wurde klar, dass arr2sich dies auf dasselbe Array bezieht arr1und nicht auf ein neues, unabhängiges Array. Wie kann ich das Array kopieren, um zwei unabhängige Arrays zu erhalten?


3
Es sieht so aus, als hätten wir derzeit in Chrome 53 und Firefox 48 eine coole Leistung für sliceund spliceOperationen sowie einen neuen Spread-Operator und Array.fromeine viel langsamere Implementierung. Schauen Sie sich perfjs.fnfo
Pencroff

jsben.ch/#/wQ9RU <= dieser Benchmark gibt einen Überblick über die verschiedenen Möglichkeiten zum Kopieren eines Arrays
EscapeNetscape


Für dieses Array (eine , die primitiven Zeichenkette enthält) können Sie verwenden , var arr2 = arr1.splice();um tiefe Kopie, aber diese Technik wird nicht funktionieren , wenn die Elemente im Array enthalten wörtliche Strukturen (zB []oder {}) oder Prototyp - Objekte (dh function () {}, newusw.). Weitere Lösungen finden Sie in meiner Antwort unten.
Montag

16
Es ist 2017, also könnten Sie die Verwendung von ES6-Funktionen in Betracht ziehen: let arr2 = [...arr1]; developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Hinrich

Antworten:


2701

Benutze das:

var newArray = oldArray.slice();

Grundsätzlich klont die slice()Operation das Array und gibt einen Verweis auf ein neues Array zurück.

Beachten Sie auch Folgendes:

Kopiert für Referenzen, Zeichenfolgen und Zahlen (und nicht das eigentliche Objekt) slice()Objektreferenzen in das neue Array. Sowohl das ursprüngliche als auch das neue Array beziehen sich auf dasselbe Objekt. Wenn sich ein referenziertes Objekt ändert, sind die Änderungen sowohl für das neue als auch für das ursprüngliche Array sichtbar.

Grundelemente wie Zeichenfolgen und Zahlen sind unveränderlich, sodass Änderungen an Zeichenfolgen oder Zahlen nicht möglich sind.


9
In Bezug auf die Leistung zeigen die folgenden jsPerf-Tests tatsächlich, dass var arr2 = arr1.slice () genauso schnell ist wie var arr2 = arr1.concat (); JSPerf: jsperf.com/copy-array-slice-vs-concat/5 und jsperf.com/copy-simple-array . Das Ergebnis von jsperf.com/array-copy/5 hat mich so überrascht, dass ich mich frage, ob der Testcode gültig ist.
Cohen

94
Obwohl dies bereits eine Menge positive Stimmen erhalten hat, verdient es eine weitere, da es Referenzen in JS richtig beschreibt, was leider eher selten ist.
Wayne

34
@ GáborImre würden Sie eine ganze Bibliothek nur zur besseren Lesbarkeit hinzufügen? "Ja wirklich?" Ich würde nur einen Kommentar hinzufügen, wenn ich so besorgt über die Lesbarkeit wäre. Siehe: var newArray = oldArray.slice (); // Klone oldArray to newArray
dudewad

12
@ GáborImre Ich verstehe das, klar. Die Beantwortung eines bestimmten technischen Problems durch die Einbeziehung einer gesamten Bibliothek ist meiner Meinung nach nicht hilfreich, da das Design aufgebläht ist. Ich sehe, dass Entwickler das oft tun, und dann haben Sie ein Projekt, das ein ganzes Framework enthält, um zu ersetzen, dass Sie eine einzelne Funktion schreiben müssen. Nur mein MO.
Dudewad

5
Lektion gelernt: Verwechseln Sie nicht .slice()mit .splice(), was Ihnen ein leeres Array gibt. Großer Unterschied.
Crazypeter

531

In Javascript hängen Deep-Copy-Techniken von den Elementen in einem Array ab. Fangen wir dort an.

Drei Arten von Elementen

Elemente können sein: Literalwerte, Literalstrukturen oder Prototypen.

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

Aus diesen Elementen können drei Arten von Arrays erstellt werden.

// 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-Techniken hängen von den drei Array-Typen ab

Basierend auf den Elementtypen im Array können wir verschiedene Techniken zum Deep Copy verwenden.

Javascript Deep Copy-Techniken nach Elementtypen

  • Array von literal-Werten (Typ 1)
    Die [...myArray], myArray.splice(0), myArray.slice()und myArray.concat()Techniken können auf tiefe Kopie Arrays mit literalen Werten verwendet werden (boolean, Anzahl und string) nur; Hier hat der Spread-Operator [...myArray]die beste Leistung ( https://measurethat.net/Benchmarks/Show/4281/0/spread-array-performance-vs-slice-splice-concat ).

  • Array von Literalwerten (Typ1) und Literalstrukturen (Typ2)
    Mit dieser JSON.parse(JSON.stringify(myArray))Technik können Literalwerte (Boolescher Wert, Zahl, Zeichenfolge) und Literalstrukturen (Array, Objekt), jedoch keine Prototypobjekte, tief kopiert werden.

  • Alle Arrays (Typ1, Typ2, Typ3)
    Mit der jQuery- $.extend(myArray)Technik können alle Array-Typen tief kopiert werden. Bibliotheken wie Underscore und Lo-Dash bieten ähnliche Deep-Copy-Funktionen wie jQuery $.extend() , weisen jedoch eine geringere Leistung auf. Überraschender ist, $.extend()hat eine höhere Leistung als die JSON.parse(JSON.stringify(myArray))Technik http://jsperf.com/js-deep-copy/15 .
    Und für Entwickler, die Bibliotheken von Drittanbietern (wie jQuery) scheuen, können Sie die folgende benutzerdefinierte Funktion verwenden. Das hat eine höhere Leistung als $ .extend und kopiert alle Arrays tief.

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

Also um die Frage zu beantworten ...

Frage

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

Mir wurde klar, dass arr2 sich auf dasselbe Array wie arr1 bezieht und nicht auf ein neues, unabhängiges Array. Wie kann ich das Array kopieren, um zwei unabhängige Arrays zu erhalten?

Antworten

Da arr1es sich um ein Array von Literalwerten (Boolescher Wert, Zahl oder Zeichenfolge) handelt, können Sie jede oben beschriebene Deep-Copy-Technik verwenden, bei der der Spread-Operator ...die höchste Leistung aufweist.

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

1
Viele dieser Ansätze funktionieren nicht gut. Die Verwendung des Zuweisungsoperators bedeutet, dass Sie den ursprünglichen Literalwert von neu zuweisen müssen arr1. Es ist sehr selten, dass dies der Fall sein wird. Verwenden Sie spliceObliterates arr1, das ist also überhaupt keine Kopie. Die Verwendung JSONschlägt fehl, wenn einer der Werte im Array Funktionen ist oder Prototypen enthält (z. B. a Date).
Dancrumb

Die Verwendung von Spleiß ist eine Teillösung. Es wird in weit mehr Fällen als JSON fehlschlagen. Splice erstellt eine tiefe Kopie von Zeichenfolgen und Zahlen, wenn Werte verschoben werden - es wurde nie gesagt, dass eine Kopie zurückgegeben wird.
tfmontague

1
Warum spleißen (0)? Sollte es nicht Slice () sein? Ich denke, es soll das ursprüngliche Array nicht modifizieren, was Spleiß tut. @ JamesMontagne
Helpse

2
Durch Spleißen werden Zeiger auf die Elemente im ursprünglichen Array erstellt (flache Kopie). splice (0) reserviert neuen Speicher (Deep Copy) für Elemente im Array, bei denen es sich um Zahlen oder Zeichenfolgen handelt, und erstellt Zeiger für alle anderen Elementtypen (flache Kopie). Durch Übergeben eines Startwerts von Null an die Spleißfunktionsmethode werden keine Elemente aus dem ursprünglichen Array gespleißt und daher nicht geändert.
Montag,

1
Tatsächlich gibt es nur einen Array-Typ: ein Array von "etwas". Es gibt keinen Unterschied zwischen [0,"1",{2:3},function random() {return 4;}, [[5,6,7],[8,9,10],[11,12,13]]]und jedem anderen Array.
wizzwizz4

189

Sie können Array-Spreads verwenden, ...um Arrays zu kopieren.

const itemsCopy = [...items];

Auch wenn Sie ein neues Array erstellen möchten, wobei das vorhandene Teil davon ist:

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

Array-Spreads werden jetzt in allen gängigen Browsern unterstützt. Wenn Sie jedoch ältere Unterstützung benötigen, verwenden Sie Typoskript oder Babel und kompilieren Sie zu ES5.

Weitere Infos zu Spreads


1
Dies funktioniert nicht für Deep Copy. Klonen Sie ein Array in JavaScript .
SNag

151

Keine jQuery erforderlich ... Arbeitsbeispiel

var arr2 = arr1.slice()

Dadurch wird das Array von der Startposition kopiert 0 bis zum Ende des Arrays kopiert.

Es ist wichtig zu beachten, dass es für primitive Typen (Zeichenfolge, Nummer usw.) wie erwartet funktioniert, und auch das erwartete Verhalten für Referenztypen zu erklären ...

Wenn Sie ein Array von Referenztypen haben, sagen Sie Typ Object. Das Array wird kopiert, aber beide Arrays enthalten Verweise auf dasselbe Object. In diesem Fall scheint das Array als Referenz kopiert zu sein, obwohl das Array tatsächlich kopiert wird.


12
Nein, das wäre keine tiefe Kopie.
Jondavidjohn

Versuche dies; var arr2 = JSON.stringify(arr1); arr2 = JSON.parse(arr2);
pradeep1991singh

2
Was ist der Unterschied zwischen dieser Antwort und der akzeptierten Antwort?
Isaac Pak

Fehler in der Konsole für Ihr angegebenes Beispiel "TypeError: window.addEvent ist keine Funktion"
Ravi Sharma

72

Eine Alternative zu sliceist concat, die auf zwei Arten verwendet werden kann. Die erste davon ist vielleicht besser lesbar, da das beabsichtigte Verhalten sehr klar ist:

var array2 = [].concat(array1);

Die zweite Methode ist:

var array2 = array1.concat();

Cohen (in den Kommentaren) wies darauf hin, dass diese letztere Methode eine bessere Leistung hat .

Die Art und Weise, wie dies funktioniert, ist, dass die concat Methode ein neues Array erstellt, das aus den Elementen in dem Objekt besteht, für das es aufgerufen wird, gefolgt von den Elementen aller Arrays, die als Argumente an sie übergeben werden. Wenn also keine Argumente übergeben werden, wird das Array einfach kopiert.

Lee Penkman weist auch in den Kommentaren darauf hin, dass Sie ein leeres Array wie folgt zurückgeben können , wenn eine Chance array1besteht undefined:

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

Oder für die zweite Methode:

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

Beachten Sie, dass Sie dies auch tun können mit slice: var array2 = (array1 || []).slice();.


31
Eigentlich können Sie auch Folgendes tun: var array2 = array1.concat (); In Bezug auf die Leistung ist es viel schneller. (JSPerf: jsperf.com/copy-simple-array und jsperf.com/copy-array-slice-vs-concat/5
Cohen

5
Es ist erwähnenswert, dass wenn array1 kein Array ist, dann [].concat(array1)zurückgegeben wird, [array1]z. B. wenn es undefiniert ist, erhalten Sie [undefined]. Ich mache manchmalvar array2 = [].concat(array1 || []);
Lee Penkman

60

So habe ich es gemacht, nachdem ich viele Ansätze ausprobiert habe:

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

Dadurch wird eine neue tiefe Kopie erstellt, die nicht mit der ersten verwandt ist (keine flache Kopie).

Auch dies wird natürlich keine Ereignisse und Funktionen klonen, aber das Gute ist, dass Sie es in einer Zeile tun können, und es kann für jede Art von Objekt (Arrays, Strings, Zahlen, Objekte ...) verwendet werden.


4
Dies ist der beste. Ich benutze die gleiche Methode vor langer Zeit und denke, dass es keinen Sinn mehr in rekursiven Schleifen der alten Schule gibt
Vladimir Kharlampidi

1
Beachten Sie, dass diese Option grafisch ähnliche Strukturen nicht gut verarbeitet: Sie stürzt bei Vorhandensein von Zyklen ab und behält keine gemeinsamen Referenzen bei.
Ruben

1
Dies scheitert auch an Dingen wie Dateoder in der Tat an allem, was einen Prototyp hat. Außerdem werden undefineds in nulls konvertiert .
Dancrumb

7
Ist niemand mutig genug, sich zu der groben Ineffizienz sowohl in der CPU als auch im Speicher zu äußern, wenn man in Text serialisiert und dann zu einem Objekt zurückspielt?
Lawrence Dol

3
Diese Lösung ist die einzige, die funktioniert hat. Die Verwendung von Slice () ist wirklich eine gefälschte Lösung.

20

Einige der genannten Methoden funktionieren gut, wenn Sie mit einfachen Datentypen wie Zahl oder Zeichenfolge arbeiten. Wenn das Array jedoch andere Objekte enthält, schlagen diese Methoden fehl. Wenn wir versuchen, ein Objekt von einem Array an ein anderes zu übergeben, wird es als Referenz übergeben, nicht als Objekt.

Fügen Sie Ihrer JavaScript-Datei den folgenden Code hinzu:

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

Und einfach benutzen

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

Es wird klappen.


2
Ich erhalte diesen Fehler, wenn ich diesen Code zu meiner Seite 'Uncaught RangeError: Maximale Größe des Aufrufstapels überschritten'
hinzufüge

1
Ich entschuldige mich, dieser Fehler tritt in Chrome auf, wenn arr1 nicht deklariert ist. Also habe ich den obigen Code kopiert und bekomme den Fehler. Wenn ich jedoch das Array arr1 deklariere, bekomme ich den Fehler nicht. Sie könnten die Antwort verbessern, indem Sie arr1 direkt über arr2 deklarieren. Ich sehe, dass es einige von uns gibt, die nicht erkannt haben, dass wir arr1 deklarieren müssen (teilweise, weil ich bei der Bewertung Ihrer Antwort in Eile war und brauchte etwas, das "einfach funktioniert")
sawe

.slice()funktioniert immer noch gut, auch wenn Sie Objekte in Ihrem Array haben: jsfiddle.net/edelman/k525g
Jason

7
@Jason, aber die Objekte zeigen immer noch auf dasselbe Objekt. Wenn Sie also eines ändern, wird das andere geändert. jsfiddle.net/k525g/1
Samuel

Hervorragender Code. Eine Frage, die ich habe, ich habe tatsächlich versucht, ein Array wie dieses in ein anderes zu kopieren var arr1 = new Array () und dann var arr2 = arr1; Wenn ich etwas in arr2 ändere, geschieht die Änderung auch in arr1. Wenn ich jedoch den von Ihnen erstellten Klonprototyp verwende, wird tatsächlich eine vollständig neue Instanz dieses Arrays erstellt oder mit anderen Worten kopiert. Ist das also ein Browserproblem? oder Javascript setzt standardmäßig die beiden Variablen so, dass eine mit Hilfe von Zeigern aufeinander zeigt, wenn jemand var arr2 = arr1 ausführt und warum dies nicht mit ganzzahligen Variablen geschieht. siehe jsfiddle.net/themhz/HbhtA
themhz


17

Ich persönlich halte Array.from für eine besser lesbare Lösung. Achten Sie übrigens nur auf die Browserunterstützung.

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

1
Ja, das ist sehr gut lesbar. Die .slice()Lösung ist völlig unintuitiv. Danke dafür.
Banago

15

Wichtig!

Die meisten Antworten hier funktionieren für bestimmte Fälle .

Wenn Sie sich nicht für tiefe / verschachtelte Objekte und Requisiten interessieren, verwenden Sie ( ES6 ):

let clonedArray = [...array]

Wenn Sie jedoch einen tiefen Klon ausführen möchten, verwenden Sie stattdessen Folgendes:

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


Für lodash Benutzer:

let clonedArray = _.clone(array) Dokumentation

und

let clonedArray = _.cloneDeep(array) Dokumentation



9

Hinzufügen zur Lösung von array.slice (); Beachten Sie, dass bei mehrdimensionalen Arrays Sub-Arrays durch Referenzen kopiert werden. Was Sie tun können, ist, jedes Sub-Array einzeln zu schleifen und zu schneiden ()

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

Das Gleiche gilt für ein Array von Objekten. Sie werden als Referenz kopiert. Sie müssen sie manuell kopieren


Diese Antwort verdient einen Platz oben auf der Seite! Ich habe mit mehrdimensionalen Sub-Arrays gearbeitet und konnte nicht verfolgen, warum die inneren Arrays immer von ref und nicht von val kopiert wurden. Diese einfache Logik löste mein Problem. Ich würde dir wenn möglich +100 geben!
Mac

8

Primitive Werte werden immer an ihrem Wert übergeben (kopiert). Zusammengesetzte Werte werden jedoch als Referenz übergeben.

Wie kopieren wir diesen Arr?

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

Kopieren Sie ein Array in ES6

let arrCopy = [...arr]; 

Kopieren Sie n Array in ES5

let arrCopy = arr.slice(); 
let arrCopy = [].concat(arr);

Warum wird "let arrCopy = arr" nicht als Wert übergeben?

Das Übergeben einer Variablen an eine andere bei zusammengesetzten Werten wie Object / Array verhält sich anders. Mit dem Operator asign für Copand-Werte übergeben wir einen Verweis auf ein Objekt. Aus diesem Grund ändert sich der Wert beider Arrays beim Entfernen / Hinzufügen von arr-Elementen.

Ausnahmen:

arrCopy[1] = 'adding new value this way will unreference';

Wenn Sie der Variablen einen neuen Wert zuweisen, ändern Sie die Referenz selbst und dies wirkt sich nicht auf das ursprüngliche Objekt / Array aus.

Weiterlesen


6

Wie wir in Javascript Arrays und Objekte wissen auf Referenz, aber wie können wir das Array kopieren, ohne das ursprüngliche Array später zu ändern?

Hier sind einige Möglichkeiten, dies zu tun:

Stellen Sie sich vor, wir haben dieses Array in Ihrem Code:

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

1) Durchlaufen Sie das Array in einer Funktion und geben Sie ein neues Array wie folgt zurück:

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

2) Mit der Slice-Methode wird Slice zum Schneiden eines Teils des Arrays verwendet. Es schneidet einen Teil Ihres Arrays, ohne das Original zu berühren. Wenn Sie im Slice nicht den Anfang und das Ende des Arrays angeben, wird das Ganze geschnitten Array und erstellen Sie im Grunde eine vollständige Kopie des Arrays, so dass wir leicht sagen können:

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

3) Auch die Kontaktmethode dient zum Zusammenführen von zwei Arrays. Wir können jedoch nur eines der Arrays angeben und dann im Grunde genommen eine Kopie der Werte im neuen kontaktierten Array erstellen:

var arr2 = arr.concat();

4) Auch die Stringify- und Parse-Methode wird nicht empfohlen, kann aber eine einfache Möglichkeit sein, Array und Objekte zu kopieren:

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

5) Die Methode Array.from wird nicht allgemein unterstützt. Überprüfen Sie vor der Verwendung die Unterstützung in verschiedenen Browsern:

const arr2 = Array.from(arr);

6) ECMA6-Weg, auch nicht vollständig unterstützt, aber babelJs können Ihnen helfen, wenn Sie transpilieren möchten:

const arr2 = [...arr];

6
let a = [1,2,3];

Jetzt können Sie eine der folgenden Aktionen ausführen, um eine Kopie eines Arrays zu erstellen.

let b = Array.from(a); 

ODER

let b = [...a];

ODER

let b = new Array(...a); 

ODER

let b = a.slice(); 

ODER

let b = a.map(e => e);

Nun, wenn ich a ändere,

a.push(5); 

Dann ist a [1,2,3,5], aber b ist immer noch [1,2,3], da es eine andere Referenz hat.

Aber ich denke, in allen oben genannten Methoden ist Array.from besser und hauptsächlich zum Kopieren eines Arrays gedacht .


1
welches ist das schnellste?
Marc Frame

5

Ich persönlich würde diesen Weg bevorzugen:

JSON.parse(JSON.stringify( originalObject ));

Also der hier vorgeschlagene Weg ?
Script47

4

In meinem speziellen Fall musste ich sicherstellen, dass das Array intakt blieb, damit dies für mich funktionierte:

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

2
+1, wenn Sie Ihrem Code keine Unklarheit hinzufügen, indem Sie eine Funktion aufrufen, die genau dasselbe tut, jedoch auf weniger offensichtliche Weise. Slice mag unter der Haube effizienter sein, aber für jeden, der am Code arbeitet, zeigt dies Ihre Absicht. Außerdem erleichtert es die spätere Optimierung, wenn Sie beispielsweise filtern möchten, was Sie kopieren. Beachten Sie jedoch, dass dies kein tiefes Kopieren ermöglicht und dass dieselben internen Objekte als Referenz an das neue Array übergeben werden. Dies ist möglicherweise das, was Sie tun möchten, möglicherweise nicht.
synchronisiert

4

Kopie des mehrdimensionalen Arrays / Objekts erstellen:

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

Vielen Dank an James Padolsey für diese Funktion.

Quelle: Hier


3

Dan, du musst keine ausgefallenen Tricks anwenden. Sie müssen lediglich eine Kopie von arr1 erstellen.

var arr2 = new Array(arr1);

Jetzt arr1und arr2sind zwei verschiedene Array-Variablen in separaten Stapeln gespeichert. Überprüfen Sie dies auf jsfiddle .


Dadurch wird das Array nicht kopiert. Es wird ein Array mit einem Element erstellt, das auf das Original verweist (dh var arr2 = [arr1];).
Timothy003

3

Wenn wir ein Array mit dem Zuweisungsoperator ( =) kopieren möchten, wird keine Kopie erstellt, sondern lediglich der Zeiger / Verweis auf das Array kopiert. Zum Beispiel:

const oldArr = [1,2,3];

const newArr = oldArr;  // now oldArr points to the same place in memory 

console.log(oldArr === newArr);  // Points to the same place in memory thus is true

const copy = [1,2,3];

console.log(copy === newArr);  // Doesn't point to the same place in memory and thus is false

Wenn wir Daten transformieren, möchten wir häufig unsere ursprüngliche Datenstruktur (z. B. Array) intakt halten. Dazu erstellen wir eine exakte Kopie unseres Arrays, damit dieses transformiert werden kann, während das ursprüngliche intakt bleibt.

Möglichkeiten zum Kopieren eines Arrays:

const oldArr = [1,2,3];

// Uses the spread operator to spread out old values into the new array literal
const newArr1 = [...oldArr];

// Slice with no arguments returns the newly copied Array
const newArr2 = oldArr.slice();

// Map applies the callback to every element in the array and returns a new array
const newArr3 = oldArr.map((el) => el);

// Concat is used to merge arrays and returns a new array. Concat with no args copies an array
const newArr4 = oldArr.concat();

// Object.assign can be used to transfer all the properties into a new array literal
const newArr5 = Object.assign([], oldArr);

// Creating via the Array constructor using the new keyword
const newArr6 = new Array(...oldArr);

// For loop
function clone(base) {
	const newArray = [];
    for(let i= 0; i < base.length; i++) {
	    newArray[i] = base[i];
	}
	return newArray;
}

const newArr7 = clone(oldArr);

console.log(newArr1, newArr2, newArr3, newArr4, newArr5, newArr6, newArr7);

Seien Sie vorsichtig, wenn Arrays oder Objekte verschachtelt sind!:

Wenn Arrays verschachtelt sind, werden die Werte als Referenz kopiert. Hier ist ein Beispiel, wie dies zu Problemen führen kann:

let arr1 = [1,2,[1,2,3]]

let arr2 = [...arr1];

arr2[2][0] = 5;  // we change arr2

console.log(arr1);  // arr1 is also changed because the array inside arr1 was copied by reference

Verwenden Sie diese Methoden also nicht, wenn sich Objekte oder Arrays in Ihrem Array befinden, die Sie kopieren möchten. dh Verwenden Sie diese Methoden nur für Arrays von Grundelementen.

Wenn Sie ein Javascript-Array tief klonen möchten, verwenden Sie Folgendes JSON.parsein Verbindung mit JSON.stringify:

let arr1 = [1,2,[1,2,3]]

let arr2 = JSON.parse(JSON.stringify(arr1)) ;

arr2[2][0] = 5;

console.log(arr1);  // now I'm not modified because I'm a deep clone

Kopierleistung:

Welches wählen wir also für eine optimale Leistung? Es stellt sich heraus, dass die forSchleife als ausführlichste Methode die höchste Leistung aufweist. Verwenden Sie diefor Schleife für wirklich CPU-intensives Kopieren (große / viele Arrays).

Danach hat die .slice()Methode auch eine anständige Leistung und ist auch weniger ausführlich und für den Programmierer einfacher zu implementieren. Ich empfehle, .slice()für das tägliche Kopieren von Arrays zu verwenden, die nicht sehr CPU-intensiv sind. Vermeiden Sie auch die Verwendung von JSON.parse(JSON.stringify(arr))(viel Overhead), wenn kein tiefer Klon erforderlich ist und die Leistung ein Problem darstellt.

Quellleistungstest


3

Wenn Ihr Array Elemente des primitiven Datentyps wie int, char oder string usw. enthält , können Sie eine dieser Methoden verwenden, die eine Kopie des ursprünglichen Arrays zurückgeben, z. B. .slice () oder .map () oder einen Spread-Operator ( dank ES6).

new_array = old_array.slice()

oder

new_array = old_array.map((elem) => elem)

oder

const new_array = new Array(...old_array);

ABER wenn Ihr Array komplexe Elemente wie Objekte (oder Arrays) oder mehr verschachtelte Objekte enthält , müssen Sie sicherstellen, dass Sie eine Kopie aller Elemente von der obersten Ebene bis zur letzten Ebene erstellen, sonst Referenz des Inneren Objekte werden verwendet und das bedeutet, dass das Ändern von Werten in object_elements in new_array weiterhin Auswirkungen auf das old_array hat. Sie können diese Kopiermethode auf jeder Ebene als TIEFKOPIE bezeichnen des old_array bezeichnen.

Für das Tiefenkopieren können Sie die oben genannten Methoden für primitive Datentypen auf jeder Ebene je nach Datentyp verwenden, oder Sie können diese kostspielige Methode (siehe unten) zum Erstellen einer Tiefenkopie verwenden, ohne viel Arbeit zu leisten.

var new_array = JSON.parse(JSON.stringify(old_array));

Es gibt viele andere Methoden, die Sie je nach Ihren Anforderungen anwenden können. Ich habe nur einige davon erwähnt, um eine allgemeine Vorstellung davon zu geben, was passiert, wenn wir versuchen, ein Array nach Wert in das andere zu kopieren .


Vielen Dank, Ihre Antwort war die einzige, die für mein Szenario gearbeitet hat
Albert Sh

2

Wenn Sie eine neue Kopie eines Objekts oder Arrays erstellen möchten, müssen Sie die Eigenschaften des Objekts oder der Elemente des Arrays explizit kopieren, z. B.:

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

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

Sie können bei Google nach weiteren Informationen zu unveränderlichen Grundwerten und veränderlichen Objektreferenzen suchen.


1
Sie müssen die Eigenschaften der Objekte des Arrays nicht explizit kopieren. Siehe Chtiwi Maleks Antwort.
Magne

2

Die Verwendung von jQuery Deep Copy kann wie folgt erfolgen:

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

2

Sie können auch den ES6-Spread-Operator verwenden, um das Array zu kopieren

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

2

Hier sind einige weitere Möglichkeiten zum Kopieren:

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



2

Schnelle Beispiele:

  1. Wenn Elemente im Array primitive Typen sind (Zeichenfolge, Zahl usw.)

var arr1 = ['a','b','c'];
// arr1 and arr2 are independent and primitive elements are stored in 
// different places in the memory
var arr2 = arr1.slice(); 
arr2.push('d');
console.log(arr1); // [ 'a', 'b', 'c' ]
console.log(arr2); // [ 'a', 'b', 'c', 'd' ]

  1. Wenn Elemente im Array Objektliterale sind, wird ein anderes Array ({}, [])

var arr1 = [{ x: 'a', y: 'b'}, [1, 2], [3, 4]];
// arr1 and arr2 are independent and reference's/addresses are stored in different
// places in the memory. But those reference's/addresses points to some common place
// in the memory.
var arr2 = arr1.slice(); 
arr2.pop();      // OK - don't affect arr1 bcos only the address in the arr2 is
                 // deleted not the data pointed by that address
arr2[0].x = 'z'; // not OK - affect arr1 bcos changes made in the common area 
                 // pointed by the addresses in both arr1 and arr2
arr2[1][0] = 9;	 // not OK - same above reason

console.log(arr1); // [ { x: 'z', y: 'b' }, [ 9, 2 ], [ 3, 4 ] ]
console.log(arr2); // [ { x: 'z', y: 'b' }, [ 9, 2 ] ]

  1. Lösung für 2 : Deep Copy von Element zu Element

var arr1 = [{ x: 'a', y: 'b'}, [1, 2], [3, 4]];
arr2 = JSON.parse(JSON.stringify(arr1));
arr2.pop();	  // OK - don't affect arr1
arr2[0].x = 'z';  // OK - don't affect arr1
arr2[1][0] = 9;	  // OK - don't affect arr1

console.log(arr1); // [ { x: 'a', y: 'b' }, [ 1, 2 ], [ 3, 4 ] ]
console.log(arr2); // [ { x: 'z', y: 'b' }, [ 9, 2 ] ]


1

Hier ist eine Variante:

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

Keine so schlechte Idee, obwohl ich lieber JSON stringify / parse anstelle von eval verwenden würde, und ein weiterer jsPerf-Vergleich wäre gut zum Auschecken. Beachten Sie auch, dass dies toSourcekein Standard ist und beispielsweise in Chrome nicht funktioniert.
dmi3y

1

Es gibt das neu eingeführte Array.from, aber leider wird es zum Zeitpunkt dieses Schreibens nur von neueren Firefox-Versionen (32 und höher) unterstützt. Es kann einfach wie folgt verwendet werden:

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

Referenz: Hier

Oder Array.prototype.mapkann mit einer Identitätsfunktion verwendet werden:

function identity(param)
{
    return param;
}

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

Referenz: Hier


+1 für die Erwähnung Array.from, die jetzt von allen gängigen Browsern außer Internet Explorer ( Quelle ) unterstützt wird. .
mgthomas99

Seien Sie sich bewusst Array.fromwerden Daten mutieren, nicht tief Kopieren / tief Klonen liefert.
Sudhansu Choudhary

1

Für ES6-Arrays mit Objekten

cloneArray(arr) {
    return arr.map(x => ({ ...x }));
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.