`Array`-Objekt
Dieser Artikel erklärt das Array-Objekt.
Ich erkläre die praktische Anwendung von Arrays Schritt für Schritt auf leicht verständliche Weise.
YouTube Video
Array-Objekt
Das Array-Objekt in JavaScript ist eine der wichtigsten Strukturen und bildet die Grundlage für alle Arten der Datenverarbeitung. Von grundlegenden Array-Operationen bis hin zu höheren Funktionen für eine effiziente Datenumwandlung gibt es viele nützliche Funktionen, die Sie kennen sollten.
Grundlagen von Arrays
In JavaScript sind Arrays eine grundlegende Datenstruktur, um mehrere Werte gemeinsam zu verwalten. Hier zeigen wir, wie man Arrays erstellt und ihre Elemente mit einfachen Beispielen liest und schreibt.
1// Create arrays in different ways
2const arr1 = [1, 2, 3]; // array literal
3const arr2 = new Array(4, 5, 6); // Array constructor
4const arr3 = Array.of(7, 8, 9); // Array.of
5
6console.log("arr1 created with literal. :", arr1);
7console.log("arr2 created with constructor:", arr2);
8console.log("arr3 created with Array.of. :", arr3);
9// arr1 created with literal. : [ 1, 2, 3 ]
10// arr2 created with constructor: [ 4, 5, 6 ]
11// arr3 created with Array.of. : [ 7, 8, 9 ]
12
13// Access and modify elements
14let first = arr1[0]; // read element
15console.log("First element of arr1:", first);
16// First element of arr1: 1
17
18arr1[1] = 20; // modify element
19console.log("arr1 after modifying index 1:", arr1);
20// arr1 after modifying index 1: [ 1, 20, 3 ]
21
22const len = arr1.length; // get length
23console.log("Length of arr1:", len);
24// Length of arr1: 3
- Dieser Code zeigt drei Arten, Arrays zu erstellen, wie man Elemente mit Indizes liest und aktualisiert sowie wie man die Länge mit der
length-Eigenschaft abruft. - Array-Literale sind am gebräuchlichsten und am lesbarsten und werden in alltäglichen Situationen am häufigsten verwendet.
Hinzufügen und Entfernen von Elementen (am Ende oder Anfang)
Mit Arrays können Sie ganz einfach Elemente am Anfang oder Ende hinzufügen oder entfernen. Diese Operationen sind auch beim Implementieren von Strukturen wie Stacks oder Queues nützlich.
1// Push and pop (stack-like)
2const stack = [];
3console.log("Initial stack:", stack);
4
5stack.push(1); // push 1
6console.log("After push(1):", stack);
7
8stack.push(2); // push 2
9console.log("After push(2):", stack);
10
11const last = stack.pop(); // pop -> 2
12console.log("Popped value:", last);
13console.log("Stack after pop():", stack);
14
15// Unshift and shift (queue-like)
16const queue = [];
17console.log("Initial queue:", queue);
18
19queue.push('a'); // add to end
20console.log("After push('a'):", queue);
21
22queue.unshift('start'); // add to front
23console.log("After unshift('start'):", queue);
24
25const firstItem = queue.shift(); // remove from front
26console.log("Shifted value:", firstItem);
27console.log("Queue after shift():", queue);
28
29// Initial stack: []
30// After push(1): [ 1 ]
31// After push(2): [ 1, 2 ]
32// Popped value: 2
33// Stack after pop(): [ 1 ]
34
35// Initial queue: []
36// After push('a'): [ 'a' ]
37// After unshift('start'): [ 'start', 'a' ]
38// Shifted value: start
39// Queue after shift(): [ 'a' ]
pushundpoparbeiten am Ende eines Arrays. Sie eignen sich ideal zur Umsetzung von Stapelstrukturen (Stacks).unshiftundshiftarbeiten am Anfang eines Arrays. Beachten Sie jedoch, dass Operationen am Anfang alle Elementindizes intern verschieben müssen, was diese zu einer aufwendigeren Operation macht.
Bearbeiten von Elementen in der Mitte (splice und slice)
Wenn Sie Elemente in der Mitte eines Arrays bearbeiten, wählen Sie zwischen splice und slice je nachdem, ob Sie das Originalarray ändern möchten oder nicht. Wenn Sie nur einen Teil eines Arrays extrahieren möchten, verwenden Sie slice; wenn Sie das Array selbst ändern möchten, zum Beispiel Elemente einfügen oder löschen, verwenden Sie splice.
1// slice (non-destructive)
2const nums = [0, 1, 2, 3, 4];
3console.log("Original nums:", nums);
4
5const part = nums.slice(1, 4); // returns [1, 2, 3]
6console.log("Result of nums.slice(1, 4):", part);
7console.log("nums after slice (unchanged):", nums);
8
9// splice (destructive)
10const arr = [10, 20, 30, 40];
11console.log("\nOriginal arr:", arr);
12
13// remove 1 item at index 2, insert 25 and 27
14arr.splice(2, 1, 25, 27);
15console.log("After arr.splice(2, 1, 25, 27):", arr);
16
17// Original nums: [ 0, 1, 2, 3, 4 ]
18// Result of nums.slice(1, 4): [ 1, 2, 3 ]
19// nums after slice (unchanged): [ 0, 1, 2, 3, 4 ]
20
21// Original arr: [ 10, 20, 30, 40 ]
22// After arr.splice(2, 1, 25, 27): [ 10, 20, 25, 27, 40 ]
sliceextrahiert nur Elemente und ändert das ursprüngliche Array nicht.splicefügt Elemente ein oder entfernt sie und ändert das Array selbst – seien Sie daher besonders vorsichtig bezüglich der Auswirkungen auf das Verhalten.
Iteration (for / for...of / forEach)
Es gibt verschiedene Möglichkeiten, Arrays sequentiell zu verarbeiten. Wählen Sie entsprechend dem Verwendungszweck und Ihrem bevorzugten Programmierstil. Hier sind drei typische Schleifen-Konstrukte.
1const items = ['apple', 'banana', 'cherry'];
2console.log("Items:", items);
3
4// classic for
5console.log("\n--- Classic for loop ---");
6for (let i = 0; i < items.length; i++) {
7 console.log(`Index: ${i}, Value: ${items[i]}`);
8}
9
10// for...of (recommended for values)
11console.log("\n--- for...of loop ---");
12for (const item of items) {
13 console.log(`Value: ${item}`);
14}
15
16// forEach (functional style)
17console.log("\n--- forEach loop ---");
18items.forEach((item, index) => {
19 console.log(`Index: ${index}, Value: ${item}`);
20});- Die
for-Schleife ist die flexibelste und ermöglicht Indexoperationen sowie eine präzise Kontrolle der Iteration mitbreakund anderen Anweisungen. for...ofbietet eine elegante Möglichkeit, mit Elementwerten umzugehen und ist hinsichtlich Lesbarkeit am ausgewogensten.forEacherlaubt einen funktionalen Programmierstil und eignet sich gut für Operationen mit Nebeneffekten wie Protokollierung oder Datenaktualisierung pro Element. Beachten Sie jedoch, dass Siebreakodercontinuenicht verwenden können, und es ist nicht für asynchrone Verarbeitung mitawaitgeeignet.
map / filter / reduce — Höhere Funktionen
map, filter und reduce sind höherwertige Funktionen, die häufig beim Transformieren, Filtern oder Aggregieren von Arrays verwendet werden. Da Sie wiederholende Verarbeitung klar ausdrücken können, wird Ihr Code einfach und leicht verständlich.
1const numbers = [1, 2, 3, 4, 5];
2console.log("Original numbers:", numbers);
3
4// map: transform each item
5const doubled = numbers.map(n => n * 2);
6console.log("\nResult of map (n * 2):", doubled);
7
8// filter: select items
9const evens = numbers.filter(n => n % 2 === 0);
10console.log("Result of filter (even numbers):", evens);
11
12// reduce: accumulate to single value
13const sum = numbers.reduce((acc, n) => acc + n, 0);
14console.log("Result of reduce (sum):", sum);
15
16// Original numbers: [ 1, 2, 3, 4, 5 ]
17// Result of map (n * 2): [ 2, 4, 6, 8, 10 ]
18// Result of filter (even numbers): [ 2, 4 ]
19// Result of reduce (sum): 15
- Diese Methoden ermöglichen es, sich in deklarativem Stil auf das gewünschte Ergebnis zu konzentrieren, was die Lesbarkeit erhöht und unerwünschte Nebeneffekte vermeidet.
find / findIndex / some / every
Hier ein Überblick über Such- und Bedingungsprüfmethoden. Sie sind nützlich, um Elemente zu finden, die bestimmte Bedingungen erfüllen, oder boolesche Prüfungen auf dem Array durchzuführen.
1const users = [
2 { id: 1, name: 'Alice' },
3 { id: 2, name: 'Bob' },
4 { id: 3, name: 'Carol' }
5];
6
7console.log("Users:", users);
8
9// Find the first user whose name is 'Bob'
10const bob = users.find(user => user.name === 'Bob');
11console.log("\nResult of find (name === 'Bob'):", bob);
12
13// Find index of the user whose id is 3
14const indexOfId3 = users.findIndex(user => user.id === 3);
15console.log("Result of findIndex (id === 3):", indexOfId3);
16
17// Check if there exists a user with id = 2
18const hasId2 = users.some(user => user.id === 2);
19console.log("Result of some (id === 2):", hasId2);
20
21// Check if all users have a numeric id
22const allHaveNumericId = users.every(user => typeof user.id === 'number');
23console.log("Result of every (id is number):", allHaveNumericId);
24// Result of find (name === 'Bob'): { id: 2, name: 'Bob' }
25// Result of findIndex (id === 3): 2
26// Result of some (id === 2): true
27// Result of every (id is number): true
findgibt das erste Element zurück, das die Bedingung erfüllt.findIndexgibt den Index des Elements zurück, das die Bedingung erfüllt.somegibttruezurück, wenn mindestens ein Element die Bedingung erfüllt.everygibttruezurück, wenn alle Elemente die Bedingung erfüllen.
Alle diese Methoden sind bei der Array-Verarbeitung sehr nützlich. Eine ihrem Zweck entsprechende Verwendung hält Ihren Code klar und übersichtlich.
Sortieren und Vergleichsfunktionen
Arrays werden mit sort sortiert, aber standardmäßig erfolgt der Vergleich als Zeichenkette, was beim Sortieren von Zahlen zu unerwarteten Ergebnissen führen kann.
1const nums = [10, 2, 33, 4];
2console.log("Original nums:", nums);
3
4// Default sort: compares elements as strings (not suitable for numbers)
5nums.sort();
6console.log("\nAfter default sort (string comparison):", nums);
7
8// Numeric ascending sort using a compare function
9nums.sort((a, b) => a - b);
10console.log("After numeric sort (a - b):", nums);
11
12// Sort objects by a property
13const people = [{ age: 30 }, { age: 20 }, { age: 25 }];
14console.log("\nOriginal people:", people);
15
16people.sort((a, b) => a.age - b.age);
17console.log("After sorting people by age:", people);
18
19// After default sort (string comparison): [ 10, 2, 33, 4 ]
20// After numeric sort (a - b): [ 2, 4, 10, 33 ]
21// Original people: [ { age: 30 }, { age: 20 }, { age: 25 } ]
22// After sorting people by age: [ { age: 20 }, { age: 25 }, { age: 30 } ]
- Beim Sortieren von Zahlen oder Objekten sollten Sie immer eine Vergleichsfunktion angeben, um die gewünschte Reihenfolge zu erreichen.
- In einer Vergleichsfunktion platziert ein negativer Rückgabewert
avorb, ein positiver Wert placeirtbvora, und 0 ändert die Reihenfolge nicht.
Array-Kopieren und Unveränderlichkeit (Immutability)
Beim Kopieren von Arrays ist es wichtig, den Unterschied zwischen 'Referenzkopie' und 'flacher Kopie' zu verstehen. Seien Sie besonders vorsichtig, wenn sich Objekte im Array befinden: Bei einer flachen Kopie werden die inneren Objekte gemeinsam verwendet.
Referenzkopie
Wenn Sie ein Array einer anderen Variablen zuweisen, wird das Array selbst nicht dupliziert; stattdessen wird die ‘Referenz’, die auf dasselbe Array zeigt, kopiert.
1const a = [1, 2, 3];
2console.log("Original a:", a);
3
4// Reference copy; modifying b also affects a
5const b = a;
6console.log("\nReference copy b = a:", b);
7// Reference copy b = a: [ 1, 2, 3 ]
8
9b[0] = 100;
10console.log("After modifying b[0] = 100:");
11console.log("a:", a); // a: [ 100, 2, 3 ] (affected)
12console.log("b:", b); // b: [ 100, 2, 3 ]
- Bei einer Referenzkopie werden Änderungen am Inhalt des Arrays mittels der kopierten Variablen auch in der ursprünglichen Variablen, die auf dasselbe Array verweist, sichtbar.
Flache Kopie
Die Verwendung von slice() oder der Spread-Syntax erzeugt eine 'flache Kopie', da nur die Werte dupliziert werden und das Original- sowie das kopierte Array als getrennte Einheiten behandelt werden.
1const a = [1, 2, 3];
2console.log("Original a:", a);
3
4// Shallow copy (new array)
5const b = a.slice();
6console.log("\nShallow copy using slice():", b);
7// Shallow copy using slice(): [ 100, 2, 3 ]
8
9const c = [...a];
10console.log("Shallow copy using spread [...a]:", c);
11// Shallow copy using spread [...a]: [ 100, 2, 3 ]
12
13// Modifying c or d does NOT affect a
14b[1] = 200;
15c[2] = 300;
16console.log("\nAfter modifying b[1] = 200 and c[2] = 300:");
17console.log("a:", a); // [ 100, 2, 3 ]
18console.log("b:", b); // [ 100, 200, 3 ]
19console.log("c:", c); // [ 100, 2, 300 ]
- Dieser Code zeigt, dass eine durch
slice()oder die Spread-Syntax erzeugte flache Kopie eines Arrays das Originalarray nicht beeinflusst.
Flache Kopie und Unveränderlichkeit
Auch wenn Sie ein Array mit einer 'flachen Kopie' duplizieren, kann es zu unbeabsichtigtem Teilen kommen, wenn das Array Objekte enthält.
1// Shallow copy doesn't clone inner objects
2const nested = [{ x: 1 }, { x: 2 }];
3console.log("\nOriginal nested:", nested);
4// Original nested: [ { x: 1 }, { x: 2 } ]
5
6const shallow = nested.slice();
7console.log("Shallow copy of nested:", shallow);
8// Shallow copy of nested: [ { x: 1 }, { x: 2 } ]
9
10// Changing inner object affects both arrays
11shallow[0].x = 99;
12console.log("\nAfter shallow[0].x = 99:");
13console.log("nested:", nested);
14console.log("shallow:", shallow);
15// nested: [ { x: 99 }, { x: 2 } ]
16// shallow: [ { x: 99 }, { x: 2 } ]
- Dieser Code zeigt, dass bei einer flachen Kopie die inneren Objekte gemeinsam genutzt werden, sodass Änderungen an diesen inneren Objekten sowohl das Originalarray als auch die Kopie betreffen.
- Wenn Sie unabhängige Daten benötigen, müssen Sie eine 'tiefe Kopie' durchführen, zum Beispiel mit
structuredClone()oder per JSON-Konvertierung.
Nützliche Hilfsmethoden
Die folgenden Hilfsmethoden werden beim Arbeiten mit Arrays häufig verwendet. Wenn Sie sie je nach Zweck richtig einsetzen, wird Ihr Code kurz und gut lesbar.
includes
Die Methode includes prüft, ob ein bestimmter Wert in einem Array enthalten ist.
1// includes: check if array contains a value
2const letters = ['a', 'b', 'c'];
3const hasB = letters.includes('b');
4console.log("letters:", letters); // [ 'a', 'b', 'c' ]
5console.log("letters.includes('b'):", hasB); // true
- In diesem Code wird die Methode
includesverwendet, um prägnant zu bestimmen, ob ein bestimmter Wert im Array vorhanden ist.
concat
Die Methode concat gibt ein neues Array zurück, an dessen Ende das angegebene Array oder die angegebenen Werte angehängt werden, wobei das Originalarray unverändert bleibt.
1// concat: merge arrays without mutation
2const a1 = [1, 2];
3const a2 = [3, 4];
4const combined = a1.concat(a2);
5console.log("a1.concat(a2):", combined); // [ 1, 2, 3, 4 ]
6console.log("a1(unchanged):", a1); // [ 1, 2 ]
- Dieser Code zeigt, dass
concatnicht destruktiv ist, sodass Sie ein neues Array erzeugen können, während das ursprüngliche erhalten bleibt.
flat
Mit der Methode flat können Sie verschachtelte Arrays einebnen.
1// flat and flatMap: flatten arrays or map + flatten in one step
2const nested = [1, [2, [3]]];
3console.log("nested:", nested); // nested: [ 1, [ 2, [ 3 ] ] ]
4console.log("nested.flat():", nested.flat()); // default depth = 1
5// nested.flat(): [ 1, 2, [ 3 ] ]
- Dieser Code zeigt das Ergebnis des Einebnens eines Arrays um eine Ebene.
- Da Sie bei
flatdie Tiefe angeben können, können Sie Verschachtelungen flexibel nach Bedarf auflösen.
flatMap
Die Methode flatMap wendet eine Transformation auf jedes Element an und flacht anschließend die Ergebnisse automatisch zu einem eindimensionalen Array ab.
1// flat and flatMap: flatten arrays or map + flatten in one step
2const words = ['hello world', 'hi'];
3console.log("words:", words); // [ 'hello world', 'hi' ]
4
5const splitWords = words.flatMap(w => w.split(' '));
6console.log("words.flatMap(w => w.split(' ')):", splitWords);
7// words.flatMap(w => w.split(' ')): [ 'hello', 'world', 'hi' ]
- Dieser Code zeigt ein Beispiel, bei dem jeder String in einem Array an Leerzeichen getrennt wird und die Ergebnisse kombiniert sowie in ein einziges Array abgeflacht werden.
join
Die Methode join erstellt einen String, indem die Elemente eines Arrays mit einem angegebenen Trennzeichen verknüpft werden.
1// join: combine elements into a string with a separator
2const csv = ['a', 'b', 'c'].join(',');
3console.log("['a', 'b', 'c'].join(','):", csv); // a,b,c
- In diesem Code wird die Methode
joinverwendet, um ein Array in einen durch Kommas getrennten String umzuwandeln.
Häufige Fallstricke
Array-Operationen wirken auf den ersten Blick einfach, aber es gibt einige Punkte, die leicht zu unerwartetem Verhalten führen können. Viele Fallstricke können im Alltag leicht übersehen werden – beachten Sie deshalb die folgenden Punkte, um die Zuverlässigkeit Ihres Codes zu erhöhen.
sort()beimArraysortiert standardmäßig per Zeichenkettenvergleich. Um Zahlen korrekt zu sortieren, müssen Sie immer eine Vergleichsfunktion angeben.- Das Kopieren von Arrays (über
slice, Spread-Syntax usw.) erzeugt nur eine flache Kopie. Wenn Ihre Arrays Objekte enthalten, seien Sie vorsichtig, da die Originaldaten versehentlich verändert werden könnten. spliceist eine destruktive Methode, die das Array direkt verändert, währendsliceeine nicht-destruktive Methode ist, die das Originalarray nicht verändert. Es ist wichtig, sie entsprechend Ihres Zwecks gezielt einzusetzen.forEachist nicht geeignet für Schleifen mit asynchroner Verarbeitung unter Verwendung vonawait. Wenn Sie asynchrone Verarbeitung zuverlässig der Reihe nach ausführen möchten, empfiehlt sich die Verwendung vonfor...of.
Praktisches Beispiel
Im Folgenden finden Sie ein Beispiel, das Array-Methoden kombiniert, um 'das Gesamtalter aus den Benutzerdaten zu berechnen, diejenigen ab 30 herauszufiltern und eine Namensliste zu erstellen.'.
1const users = [
2 { name: 'Alice', age: 28 },
3 { name: 'Bob', age: 34 },
4 { name: 'Carol', age: 41 },
5 { name: 'Dave', age: 19 }
6];
7
8console.log("Users:", users);
9
10// sum ages
11const totalAge = users.reduce((acc, u) => acc + u.age, 0);
12console.log("\nTotal age of all users:", totalAge);
13// Total age of all users: 122
14
15// filter and map names of users 30 and older
16const namesOver30 = users
17 .filter(u => u.age >= 30)
18 .map(u => u.name);
19
20console.log("Users aged 30 or older (names):", namesOver30);
21// Users aged 30 or older (names): [ 'Bob', 'Carol' ]
- Durch das Verketten von
reduce,filterundmaplassen sich Aggregation, Bedingungsextraktion und Transformation von Daten einfach ausdrücken. - Eine solche 'Datenverarbeitungspipeline' ist sehr gut lesbar und wird wegen ihrer geringen Seiteneffekte häufig in der Praxis verwendet.
Zusammenfassung
Mit JavaScript-Arrays sind selbst Basisoperationen vielseitig einsetzbar, und durch höhere Funktionen wird Ihr Code prägnanter und ausdrucksstärker. Es gibt viele Aspekte zu verstehen, aber wenn Sie den gezielten Einsatz beherrschen, wird die Datenverarbeitung wesentlich reibungsloser ablaufen.
Sie können den obigen Artikel mit Visual Studio Code auf unserem YouTube-Kanal verfolgen. Bitte schauen Sie sich auch den YouTube-Kanal an.