Hacks zum Erstellen von JavaScript-Arrays

Aufschlussreiche Tipps zum Erstellen und Klonen von Arrays in JavaScript.

Ein sehr wichtiger Aspekt jeder Programmiersprache sind die in der Sprache verfügbaren Datentypen und Strukturen. Die meisten Programmiersprachen bieten Datentypen zum Darstellen und Arbeiten mit komplexen Daten. Wenn Sie mit Sprachen wie Python oder Ruby gearbeitet haben, sollten Sie Datentypen wie Listen , Mengen , Tupel , Hashes , Diktate usw. gesehen haben.

In JavaScript gibt es nicht so viele komplexe Datentypen - Sie haben einfach Arrays und Objekte . In ES6 wurden der Sprache jedoch einige Datentypen und -strukturen hinzugefügt, z. B. Symbole , Mengen und Karten .

Arrays in JavaScript sind listenähnliche Objekte auf hoher Ebene mit einer Längeneigenschaft und ganzzahligen Eigenschaften als Indizes.

In diesem Artikel teile ich einige Hacks zum Erstellen neuer JavaScript-Arrays oder zum Klonen bereits vorhandener.

Erstellen von Arrays: Der Array-Konstruktor

Die beliebteste Methode zum Erstellen von Arrays ist die Verwendung der Array-Literal- Syntax, die sehr einfach ist. Wenn Sie jedoch dynamisch Arrays erstellen möchten, ist die Array-Literal-Syntax möglicherweise nicht immer die beste Methode. Eine alternative Methode ist die Verwendung des ArrayKonstruktors.

Hier ist ein einfaches Code-Snippet, das die Verwendung des ArrayKonstruktors zeigt.

Aus dem vorherigen Snippet können wir erkennen, dass der ArrayKonstruktor Arrays je nach den empfangenen Argumenten unterschiedlich erstellt.

Neue Arrays: Mit definierter Länge

Schauen wir uns genauer an, was passiert, wenn ein neues Arraymit einer bestimmten Länge erstellt wird. Der Konstruktor setzt nur die lengthEigenschaft des Arrays auf die angegebene Länge, ohne die Schlüssel festzulegen.

Aufgrund des obigen Snippets könnten Sie versucht sein zu glauben, dass jeder Schlüssel im Array auf den Wert von gesetzt wurde undefined. Die Realität ist jedoch, dass diese Schlüssel nie gesetzt wurden (sie existieren nicht).

Die folgende Abbildung macht es klarer:

Dies macht es nutzlos einen der Array Iterationsverfahren zu verwenden , um zu versuchen , wie zum Beispiel map(), filter()oder reduce()das Array zu manipulieren. Angenommen, wir möchten jeden Index im Array mit der Zahl 5als Wert füllen . Wir werden Folgendes versuchen:

Wir können sehen, dass map()dies hier nicht funktioniert hat, da die Indexeigenschaften im Array nicht vorhanden sind - nur die lengthEigenschaft ist vorhanden.

Sehen wir uns verschiedene Möglichkeiten an, wie wir dieses Problem beheben können.

1. Verwenden von Array.prototype.fill ()

Die fill()Methode füllt alle Elemente eines Arrays von einem Startindex bis zu einem Endindex mit einem statischen Wert. Der Endindex ist nicht enthalten. Hier erfahren Sie mehr darüber fill().

Beachten Sie, dass dies fill()nur in Browsern mit ES6-Unterstützung funktioniert.

Hier ist eine einfache Illustration:

Hier konnten wir alle Elemente unseres erstellten Arrays mit füllen 5. Mit der fill()Methode können Sie einen beliebigen statischen Wert für verschiedene Indizes des Arrays festlegen .

2. Verwenden von Array.from ()

Die Array.from()Methode erstellt eine neue, flach kopierte ArrayInstanz aus einem Array-ähnlichen oder iterierbaren Objekt. Hier erfahren Sie mehr darüber Array.from().

Beachten Sie, dass dies Array.from()nur in Browsern mit ES6-Unterstützung funktioniert.

Hier ist eine einfache Illustration:

Hier haben wir jetzt wahre undefinedWerte für jedes Element des Arrays mit Array.from(). Dies bedeutet, dass wir jetzt Methoden wie .map()und .filter()für das Array verwenden können, da die Indexeigenschaften jetzt vorhanden sind.

Eine weitere erwähnenswerte Sache Array.from()ist, dass ein zweites Argument erforderlich ist, nämlich eine Kartenfunktion. Es wird für jedes Element des Arrays aufgerufen. Dies macht es überflüssig, .map()danach anzurufen Array.from().

Hier ist ein einfaches Beispiel:

3. Verwenden des Spread-Operators

Der Spread-Operator( ...), hinzugefügt in ES6, kann verwendet werden, um die Elemente des Arrays zu verteilen und die fehlenden Elemente auf den Wert von zu setzen undefined. Dies führt zu demselben Ergebnis wie ein einfacher Aufruf Array.from()mit nur dem Array als einzigem Argument.

Hier ist eine einfache Darstellung der Verwendung des Spread-Operators:

Sie können Methoden wie .map()und .filter()für das Array verwenden, da die Indexeigenschaften jetzt vorhanden sind.

Verwenden von Array.of ()

Genau wie wir beim Erstellen neuer Arrays mit dem ArrayKonstruktor oder der Funktion gesehen haben, Array.of()verhält es sich sehr ähnlich. Tatsächlich besteht der einzige Unterschied zwischen Array.of()und Arraydarin, wie sie mit einem einzelnen an sie übergebenen ganzzahligen Argument umgehen.

Während Array.of(5)ein neues Array mit einem einzelnen Element 5und einer Längeneigenschaft von erstellt wird 1, Array(5)wird ein neues leeres Array mit 5 leeren Slots und einer Längeneigenschaft von erstellt 5.

var array1 = Array.of(5); // [5] var array2 = Array(5); // Array(5) {length: 5}

Verhält sich neben diesem großen Unterschied Array.of()genauso wie der ArrayKonstruktor. Hier erfahren Sie mehr darüber Array.of().

Beachten Sie, dass dies Array.of()nur in Browsern mit ES6-Unterstützung funktioniert.

Konvertieren in Arrays: Array-Likes und Iterables

Wenn Sie JavaScript-Funktionen lange genug geschrieben haben, sollten Sie bereits über das argumentsObjekt Bescheid wissen. Hierbei handelt es sich um ein Array-ähnliches Objekt, das in jeder Funktion verfügbar ist, um die Liste der Argumente zu speichern, die die Funktion erhalten hat. Obwohl das argumentsObjekt einem Array sehr ähnlich sieht, hat es keinen Zugriff auf die Array.prototypeMethoden.

Vor ES6 wurde normalerweise ein Codefragment wie das folgende angezeigt, wenn Sie versuchen, das argumentsObjekt in ein Array zu konvertieren :

Mit Array.from()oder dem Spread-Operator können Sie jedes Array-ähnliche Objekt bequem in ein Array konvertieren. Anstatt dies zu tun:

var args = Array.prototype.slice.call(arguments);

Sie können eine der folgenden Aktionen ausführen:

// Using Array.from() var args = Array.from(arguments); // Using the Spread operator var args = [...arguments];

Diese gelten auch für Iterables, wie in der folgenden Abbildung dargestellt:

Fallstudie: Bereichsfunktion

Bevor wir fortfahren, werden wir als Fallstudie eine einfache range()Funktion erstellen , um den neuen Array-Hack zu implementieren, den wir gerade gelernt haben. Die Funktion hat folgende Signatur:

range(start: number, end: number, step: number) => Array

Hier ist das Code-Snippet:

In diesem Codeausschnitt haben wir Array.from()das neue Bereichsarray mit dynamischer Länge erstellt und es dann mit sequentiell inkrementierten Zahlen gefüllt, indem wir eine Zuordnungsfunktion bereitgestellt haben.

Beachten Sie, dass das obige Code-Snippet für Browser ohne ES6-Unterstützung nur funktioniert, wenn Sie Polyfills verwenden.

Hier sind einige Ergebnisse aus dem Aufruf der range()im obigen Codeausschnitt definierten Funktion:

Sie können eine Live-Code-Demo erhalten, indem Sie den folgenden Stift auf Codepen ausführen :

Klonen von Arrays: Die Herausforderung

In JavaScript sind Arrays und Objekte Referenztypen. Dies bedeutet, dass, wenn einer Variablen ein Array oder Objekt zugewiesen wird, der Variablen ein Verweis auf den Speicherort im Speicher zugewiesen wird, an dem das Array oder Objekt gespeichert wurde.

Arrays sind wie jedes andere Objekt in JavaScript Referenztypen. Dies bedeutet, dass Arrays nach Referenz und nicht nach Wert kopiert werden.

Das Speichern von Referenztypen auf diese Weise hat folgende Konsequenzen:

1. Ähnliche Arrays sind nicht gleich.

Hier sehen wir, dass array1und obwohl array2sie scheinbar die gleichen Array-Spezifikationen enthalten, sie nicht gleich sind. Dies liegt daran, dass der Verweis auf jedes der Arrays auf eine andere Position im Speicher verweist.

2. Arrays werden als Referenz und nicht als Wert kopiert.

Hier versuchen wir , zu kopieren , array1zu array2, aber was wir im Grunde tun , zeigen array2auf die gleiche Stelle in Erinnerung , dass array1Punkte auf. Daher zeigen beide array1und array2auf dieselbe Stelle im Speicher und sind gleich.

Dies hat zur Folge, dass bei einer Änderung array2durch Entfernen des letzten Elements auch das letzte Element von array1entfernt wird. Dies liegt daran, dass die Änderung tatsächlich an dem im Speicher gespeicherten Array vorgenommen wurde, während array1und array2nur Zeiger auf denselben Speicherort im Speicher sind, an dem das Array gespeichert ist.

Klonen von Arrays: The Hacks

1. Verwenden von Array.prototype.slice ()

Die slice()Methode erstellt eine flache Kopie eines Teils eines Arrays, ohne das Array zu ändern. Hier erfahren Sie mehr darüber slice().

Der Trick besteht darin, slice()entweder mit 0als einzigem Argument oder ohne Argumente aufzurufen :

// with O as only argument array.slice(0); // without argument array.slice();

Hier ist eine einfache Darstellung des Klonens eines Arrays mit slice():

Hier sehen Sie, dass array2es sich um einen Klon array1mit denselben Elementen und derselben Länge handelt. Sie verweisen jedoch auf unterschiedliche Speicherorte im Speicher und sind daher nicht gleich. Sie bemerken auch, dass, wenn wir eine Änderung array2durch Entfernen des letzten Elements vornehmen , diese array1unverändert bleibt.

2. Verwenden von Array.prototype.concat ()

Die concat()Methode wird verwendet, um zwei oder mehr Arrays zusammenzuführen, was zu einem neuen Array führt, während die ursprünglichen Arrays unverändert bleiben. Hier erfahren Sie mehr darüber concat().

Der Trick besteht darin, concat()entweder mit einem leeren Array ( []) als Argument oder ohne Argumente aufzurufen :

// with an empty array array.concat([]); // without argument array.concat();

Das Klonen eines Arrays mit concat()ist dem Verwenden ziemlich ähnlich slice(). Hier ist eine einfache Darstellung des Klonens eines Arrays mit concat():

3. Verwenden von Array.from ()

Wie wir bereits gesehen haben, Array.from()kann ein neues Array erstellt werden, das eine flache Kopie des ursprünglichen Arrays ist. Hier ist eine einfache Illustration:

4. Verwenden der Array-Destrukturierung

Mit ES6 haben wir einige leistungsfähigere Tools in unserer Toolbox, z. B. Destrukturierung , VerbreitungOperator , Pfeilfunktionen und so weiter. Die Destrukturierung ist ein sehr leistungsfähiges Werkzeug zum Extrahieren von Daten aus komplexen Typen wie Arrays und Objekten.

Der Trick besteht darin, eine Technik namens Restparameter zu verwenden, die eine Kombination aus Array-Destrukturierung und Spread-Operator umfasst, wie im folgenden Snippet gezeigt:

let [...arrayClone] = originalArray;

Das obige Snippet erstellt eine Variable mit dem Namen, arrayClonedie ein Klon von ist originalArray. Hier ist eine einfache Darstellung des Klonens eines Arrays mithilfe der Array-Destrukturierung:

Klonen: Flach gegen tief

Alle bisher untersuchten Array-Klontechniken erzeugen eine flache Kopie des Arrays. Dies ist kein Problem, wenn das Array nur primitive Werte enthält. Wenn das Array jedoch verschachtelte Objektreferenzen enthält, bleiben diese Referenzen auch dann intakt, wenn das Array geklont wird.

Hier ist eine sehr einfache Demonstration davon:

Beachten Sie, dass durch Ändern des verschachtelten Arrays array1auch das verschachtelte Array geändert wurde array2und umgekehrt.

Die Lösung für dieses Problem besteht darin, eine tiefe Kopie des Arrays zu erstellen. Dazu gibt es verschiedene Möglichkeiten.

1. Die JSON-Technik

Der einfachste Weg, eine tiefe Kopie eines Arrays zu erstellen, ist die Verwendung einer Kombination aus JSON.stringify()und JSON.parse().

JSON.stringify()konvertiert einen JavaScript-Wert in eine gültige JSON-Zeichenfolge, während JSON.parse()eine JSON-Zeichenfolge in einen entsprechenden JavaScript-Wert oder ein Objekt konvertiert wird.

Hier ist ein einfaches Beispiel:

Die JSON-Technik weist einige Mängel auf, insbesondere wenn andere Werte als Zeichenfolgen, Zahlen und Boolesche Werte betroffen sind.

Diese Fehler in der JSON-Technik können hauptsächlich auf die Art und Weise zurückgeführt werden, in der die JSON.stringify()Methode Werte in JSON-Zeichenfolgen konvertiert.

Hier ist eine einfache Demonstration dieses Fehlers beim Versuch, JSON.stringify()einen Wert zu finden, der verschachtelte Funktionen enthält.

2. Deep Copy Helper

Eine praktikable Alternative zur JSON-Technik besteht darin, eine eigene Deep Copy-Hilfsfunktion zum Klonen von Referenztypen zu implementieren, unabhängig davon, ob es sich um Arrays oder Objekte handelt.

Hier ist eine sehr einfache und minimalistische Deep-Copy-Funktion namens deepClone:

Dies ist nicht die beste Deep-Copy-Funktion, wie Sie bald bei einigen JavaScript-Bibliotheken sehen werden. Sie führt jedoch ein ziemlich gutes Deep-Copy-Verfahren durch.

3. Verwenden von JavaScript-Bibliotheken

Die soeben definierte Deep Copy-Hilfsfunktion ist nicht robust genug, um alle Arten von JavaScript-Daten zu klonen, die in komplexen Objekten oder Arrays verschachtelt sein können.

JavaScript-Bibliotheken wie Lodash und jQuery bieten robustere Deep Copy-Dienstprogrammfunktionen mit Unterstützung für verschiedene Arten von JavaScript-Daten.

Hier ist ein Beispiel _.cloneDeep()aus der Lodash-Bibliothek:

Hier ist das gleiche Beispiel, jedoch unter Verwendung $.extend()aus der jQuery-Bibliothek:

Fazit

In diesem Artikel konnten wir verschiedene Techniken zum dynamischen Erstellen neuer Arrays und zum Klonen bereits vorhandener Arrays untersuchen, einschließlich des Konvertierens von Array-ähnlichen Objekten und Iterables in Arrays.

Wir haben auch gesehen, wie einige der in ES6 eingeführten neuen Funktionen und Verbesserungen es uns ermöglichen können, bestimmte Manipulationen an Arrays effektiv durchzuführen.

Wir haben Funktionen wie Destrukturierung und den Spread-Operator zum Klonen und Spreizen von Arrays verwendet. Weitere Informationen zur Destrukturierung finden Sie in diesem Artikel.

Klatschen & Folgen

Wenn Sie diesen Artikel aufschlussreich fanden, können Sie einige Applausrunden geben, wenn Sie nichts dagegen haben.

Sie können mir auch auf Medium (Glad Chinda) folgen, um weitere aufschlussreiche Artikel zu erhalten, die Sie möglicherweise hilfreich finden. Sie können mir auch auf Twitter (@gladchinda) folgen.

Viel Spaß beim Hacken…