Frage Array nach Wert in JavaScript kopieren


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']

Das habe ich bemerkt arr2 bezieht sich auf das gleiche Array wie arr1, und nicht ein neues, unabhängiges Array. Wie kann ich das Array kopieren, um zwei unabhängige Arrays zu erhalten?


1335
2017-09-20 13:38


Ursprung


Antworten:


Benutze das:

var newArray = oldArray.slice();

Grundsätzlich, die Scheibe() Die Operation klont das Array und gibt den Verweis auf das neue Array zurück. Beachten Sie auch Folgendes:

Bei Referenzen, Strings und Zahlen (und nicht beim tatsächlichen Objekt) kopiert 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 für das neue und das ursprüngliche Array sichtbar.

Primitive wie Strings und Zahlen sind unveränderlich, so dass Änderungen an der Zeichenkette oder Nummer unmöglich sind.


2152
2017-09-20 13:41



In JavaScript hängen Deep-Copy-Techniken von den Elementen in einem Array ab.
Lass uns dort anfangen.

Drei Arten von Elementen

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

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

Aus diesen Elementen können wir drei Arten von Arrays erstellen.

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

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

Javascript deep copy techniques by element types

  • Array von Literalwerten (Typ1)
    Das myArray.splice(0), myArray.slice(), und myArray.concat() Techniken können verwendet werden, um Arrays mit literalen Werten (Boolean, Zahl und String) nur tief zu kopieren; wo Slice eine höhere Leistung als Concat hat (http://jsperf.com/duplicate-array-slice-vs-concat/3).

  • Array von Literal-Werten (Typ1) und Literal-Strukturen (Typ2)
    Das JSON.parse(JSON.stringify(myArray)) Technik kann verwendet werden, um literale Werte (Boolean, Zahl, String) und literale Strukturen (Array, Objekt) tief zu kopieren, aber keine Prototyp-Objekte.

  • Alle Arrays (Typ1, Typ2, Typ3)
    Die jQuery $.extend(myArray) Mit dieser Technik können alle Array-Typen tiefkopiert werden. Bibliotheken mögen Unterstreichen und Streiche bieten ähnliche Deep-Copy-Funktionen an jQuery  $.extend(), haben jedoch eine geringere Leistung. Überraschender, $.extend() hat eine höhere Leistung als die JSON.parse(JSON.stringify(myArray)) Technik http://jsperf.com/js-deep-copy/15.
    Und für diejenigen Entwickler, die sich vor Drittanbieter-Bibliotheken (wie jQuery) scheuen, können Sie die folgende benutzerdefinierte Funktion verwenden; die eine höhere Leistung als $ .extend hat und alle Arrays tief kopiert.

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

Also um die Frage zu beantworten ...

Frage 

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

Ich erkannte, dass sich arr2 auf das gleiche Array wie arr1 bezieht und nicht auf a   neues, unabhängiges Array. Wie kann ich das Array kopieren, um zwei zu erhalten   unabhängige Arrays?

Antworten 

weil arr1 ist ein Array von literalen Werten (Boolean, Zahl oder String). Sie können jede oben beschriebene Tiefkopietechnik verwenden, wobei slice hat die höchste Leistung.

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

363
2018-05-08 08:36



Keine jQuery benötigt ... Arbeitsbeispiel

var arr2 = arr1.slice()

Dies übernimmt das Array von der Startposition 0 bis zum Ende des Arrays.

Es ist wichtig zu beachten, dass es für primitive Typen (String, Zahl, etc.) wie erwartet funktioniert und auch das erwartete Verhalten für Referenztypen erklärt ...

Wenn Sie ein Array von Referenztypen haben, sagen Sie vom Typ Object. Das Array werden kopiert werden, aber beide Arrays enthalten Verweise auf dasselbe Objectist es. In diesem Fall scheint es so, als würde das Array durch Verweis kopiert, obwohl das Array wird tatsächlich kopiert.


146
2017-09-20 13:39



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

const itemsCopy = [...items];

Auch wenn Sie ein neues Array erstellen möchten, mit dem vorhandenen Teil:

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

Array-Spreads sind jetzt unterstützt in allen gängigen Browsern Wenn Sie jedoch ältere Unterstützung benötigen, verwenden Sie typescript oder babel und kompilieren Sie nach ES5.

Weitere Informationen zu den Spreads


136
2017-07-03 14:46



Eine Alternative zu slice ist concat, die auf 2 Arten verwendet werden können. Der erste von diesen ist vielleicht lesbarer, 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 hat eine bessere Leistung.

Das funktioniert so, dass die concat Methode erstellt ein neues Array, bestehend aus den Elementen in dem Objekt, an dem es aufgerufen wird, gefolgt von den Elementen aller Arrays, die als Argumente übergeben werden. Wenn also keine Argumente übergeben werden, wird das Array einfach kopiert.

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

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

Oder, für die zweite Methode:

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

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


67
2017-10-18 00:11



So habe ich es nach vielen Versuchen versucht:

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

Dadurch wird eine neue tiefe Kopie erstellt, die nicht mit der ersten Kopie zusammenhängt (keine flache Kopie).

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


39
2018-04-23 13:32



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 zu einem anderen zu übergeben, wird es als Referenz übergeben, nicht als Objekt.

Fügen Sie den folgenden Code in Ihre JavaScript-Datei ein:

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.


17
2017-12-12 16:22



Von ES2015,

var arr2 = [...arr1];

14
2017-12-24 07:14



Persönlich denke ich Array.von ist eine besser lesbare Lösung. Übrigens, hüte dich vor der Browser-Unterstü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);

14
2018-03-09 12:01



Wenn Sie in einer Umgebung von sind ECMAScript 6, Verwendung der Spread Operator Du könntest es so machen:

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>


10
2017-07-03 09:31



Hinzufügen zur Lösung von array.slice (); sei dir bewusst, wenn du es getan hast mehrdimensionales Array Sub-Arrays werden durch Referenzen kopiert. Was Sie tun können, ist, jedes Sub-Array einzeln zu schleifen und zu teilen

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 das Array von Objekten, sie werden als Referenz kopiert, Sie müssen sie manuell kopieren


9
2018-04-15 13:40