JavaScript Fortgeschritten

Arrays im Detail verstehen

Arrays im Detail verstehen

Arrays sind eine der wichtigsten Datenstrukturen in JavaScript. In diesem Tutorial gehst du über die Grundlagen hinaus und lernst Arrays wirklich zu meistern.

Arrays erstellen

Verschiedene Wege

// 1. Array-Literal (empfohlen)
const zahlen = [1, 2, 3, 4, 5];

// 2. Array-Konstruktor
const leer = new Array();          // []
const mitLaenge = new Array(5);    // [empty × 5] - Vorsicht!
const mitWerten = new Array(1, 2, 3);  // [1, 2, 3]

// 3. Array.of() - Konsistenter als Konstruktor
const arr1 = Array.of(5);          // [5] - nicht [empty × 5]!
const arr2 = Array.of(1, 2, 3);    // [1, 2, 3]

// 4. Array.from() - Aus Iterable erstellen
const fromString = Array.from("Hallo");   // ["H", "a", "l", "l", "o"]
const fromSet = Array.from(new Set([1, 2, 3]));  // [1, 2, 3]

// 5. Spread-Operator
const original = [1, 2, 3];
const kopie = [...original];       // [1, 2, 3] - neue Referenz!

Arrays mit Werten füllen

// Array mit gleichem Wert füllen
const fuenf_nullen = new Array(5).fill(0);
// [0, 0, 0, 0, 0]

// Array mit Index-Werten
const indizes = Array.from({ length: 5 }, (_, i) => i);
// [0, 1, 2, 3, 4]

// Array mit berechneten Werten
const quadrate = Array.from({ length: 5 }, (_, i) => i * i);
// [0, 1, 4, 9, 16]

// Zufallszahlen
const zufall = Array.from({ length: 10 }, () => Math.floor(Math.random() * 100));
// [42, 17, 83, ...] (zufällig)

Array-Eigenschaften

length

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

console.log(arr.length);  // 5

// length ist schreibbar!
arr.length = 3;
console.log(arr);  // [1, 2, 3] - abgeschnitten!

arr.length = 5;
console.log(arr);  // [1, 2, 3, empty × 2] - mit Löchern!

// Array leeren
arr.length = 0;
console.log(arr);  // []

Sparse Arrays (mit Löchern)

const sparse = [1, , , 4];  // Löcher!
console.log(sparse.length);  // 4
console.log(sparse[1]);      // undefined
console.log(1 in sparse);    // false - Index existiert nicht!

// Unterschied zu undefined-Wert
const mitUndefined = [1, undefined, undefined, 4];
console.log(1 in mitUndefined);  // true - Index existiert

Elemente zugreifen & ändern

Lesen

const arr = ["a", "b", "c", "d", "e"];

// Positiver Index
console.log(arr[0]);   // "a"
console.log(arr[2]);   // "c"

// Negativer Index - geht NICHT direkt!
console.log(arr[-1]);  // undefined

// Letztes Element
console.log(arr[arr.length - 1]);  // "e"

// Mit at() - moderne Methode mit negativem Index!
console.log(arr.at(0));    // "a"
console.log(arr.at(-1));   // "e" - Letztes!
console.log(arr.at(-2));   // "d" - Vorletztes!

Schreiben

const arr = [1, 2, 3];

// Element ändern
arr[0] = 10;
console.log(arr);  // [10, 2, 3]

// Element am Ende hinzufügen
arr[arr.length] = 4;
console.log(arr);  // [10, 2, 3, 4]

// Lücke erzeugen (vermeiden!)
arr[10] = 99;
console.log(arr);  // [10, 2, 3, 4, empty × 6, 99]
console.log(arr.length);  // 11

Elemente hinzufügen & entfernen

Am Ende (push/pop)

const stack = [];

// push - am Ende hinzufügen
stack.push("a");          // ["a"]
stack.push("b", "c");     // ["a", "b", "c"]

const laenge = stack.push("d");
console.log(laenge);  // 4 - push gibt neue Länge zurück

// pop - vom Ende entfernen
const letztes = stack.pop();
console.log(letztes);  // "d"
console.log(stack);    // ["a", "b", "c"]

Am Anfang (unshift/shift)

const queue = [1, 2, 3];

// unshift - am Anfang hinzufügen
queue.unshift(0);         // [0, 1, 2, 3]
queue.unshift(-2, -1);    // [-2, -1, 0, 1, 2, 3]

// shift - vom Anfang entfernen
const erstes = queue.shift();
console.log(erstes);  // -2
console.log(queue);   // [-1, 0, 1, 2, 3]

Irgendwo (splice)

splice ist das Swiss Army Knife für Arrays:

const arr = ["a", "b", "c", "d", "e"];

// Entfernen: splice(startIndex, anzahlZuEntfernen)
const entfernt = arr.splice(2, 2);
console.log(entfernt);  // ["c", "d"]
console.log(arr);       // ["a", "b", "e"]

// Einfügen: splice(startIndex, 0, ...elemente)
arr.splice(2, 0, "x", "y");
console.log(arr);  // ["a", "b", "x", "y", "e"]

// Ersetzen: splice(startIndex, anzahl, ...neueElemente)
arr.splice(1, 2, "NEU");
console.log(arr);  // ["a", "NEU", "y", "e"]

Moderne Alternative: toSpliced()

toSpliced() verändert das Original nicht:

const original = [1, 2, 3, 4, 5];

const neues = original.toSpliced(2, 1, 99);
console.log(neues);     // [1, 2, 99, 4, 5]
console.log(original);  // [1, 2, 3, 4, 5] - unverändert!

Arrays kopieren

Shallow Copy (flache Kopie)

const original = [1, 2, [3, 4]];

// Spread-Operator
const kopie1 = [...original];

// slice()
const kopie2 = original.slice();

// Array.from()
const kopie3 = Array.from(original);

// Alle sind flache Kopien!
kopie1[0] = 99;
console.log(original[0]);  // 1 - unverändert

kopie1[2][0] = 99;  // Nested Array ändern
console.log(original[2][0]);  // 99 - auch geändert! 😱

Deep Copy (tiefe Kopie)

const original = [1, 2, [3, 4]];

// Mit JSON (einfach, aber limitiert)
const tiefKopie = JSON.parse(JSON.stringify(original));
tiefKopie[2][0] = 99;
console.log(original[2][0]);  // 3 - unverändert! ✅

// Mit structuredClone (modern)
const tiefKopie2 = structuredClone(original);

Arrays durchsuchen

indexOf / lastIndexOf

const arr = [1, 2, 3, 2, 1];

console.log(arr.indexOf(2));      // 1 - erste Position
console.log(arr.lastIndexOf(2));  // 3 - letzte Position
console.log(arr.indexOf(99));     // -1 - nicht gefunden

includes

const arr = [1, 2, 3, NaN];

console.log(arr.includes(2));     // true
console.log(arr.includes(99));    // false
console.log(arr.includes(NaN));   // true - funktioniert mit NaN!
console.log(arr.indexOf(NaN));    // -1 - indexOf findet NaN nicht!

find / findIndex

const users = [
    { id: 1, name: "Max" },
    { id: 2, name: "Lisa" },
    { id: 3, name: "Tom" }
];

// Objekt finden
const user = users.find(u => u.id === 2);
console.log(user);  // { id: 2, name: "Lisa" }

// Index finden
const index = users.findIndex(u => u.id === 2);
console.log(index);  // 1

// Nicht gefunden
const notFound = users.find(u => u.id === 99);
console.log(notFound);  // undefined

findLast / findLastIndex (neu!)

const zahlen = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

// Letztes Element das Bedingung erfüllt
const letzteGerade = zahlen.findLast(n => n % 2 === 0);
console.log(letzteGerade);  // 10

const index = zahlen.findLastIndex(n => n % 2 === 0);
console.log(index);  // 9

Arrays prüfen

Array.isArray()

console.log(Array.isArray([1, 2, 3]));  // true
console.log(Array.isArray("abc"));      // false
console.log(Array.isArray({ length: 3 }));  // false

every / some

const zahlen = [2, 4, 6, 8, 10];

// every - ALLE müssen true sein
const alleGerade = zahlen.every(n => n % 2 === 0);
console.log(alleGerade);  // true

// some - MINDESTENS EINER muss true sein
const hatGroesserAlsFuenf = zahlen.some(n => n > 5);
console.log(hatGroesserAlsFuenf);  // true

// Praktisches Beispiel
const users = [
    { name: "Max", active: true },
    { name: "Lisa", active: true },
    { name: "Tom", active: false }
];

const alleAktiv = users.every(u => u.active);    // false
const einerAktiv = users.some(u => u.active);    // true

Arrays sortieren

sort()

// Achtung: sort() verändert das Original!
const zahlen = [10, 2, 5, 1, 8];

// Standard-sort() sortiert als STRINGS!
zahlen.sort();
console.log(zahlen);  // [1, 10, 2, 5, 8] - falsch!

// Numerisch sortieren
zahlen.sort((a, b) => a - b);
console.log(zahlen);  // [1, 2, 5, 8, 10] - richtig!

// Absteigend
zahlen.sort((a, b) => b - a);
console.log(zahlen);  // [10, 8, 5, 2, 1]

toSorted() - ohne Mutation

const original = [3, 1, 2];
const sortiert = original.toSorted((a, b) => a - b);

console.log(sortiert);  // [1, 2, 3]
console.log(original);  // [3, 1, 2] - unverändert!

Objekte sortieren

const personen = [
    { name: "Clara", alter: 25 },
    { name: "Anna", alter: 30 },
    { name: "Ben", alter: 20 }
];

// Nach Alter
personen.sort((a, b) => a.alter - b.alter);

// Nach Name
personen.sort((a, b) => a.name.localeCompare(b.name));

Arrays umdrehen

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

// reverse() verändert Original
arr.reverse();
console.log(arr);  // [5, 4, 3, 2, 1]

// toReversed() ohne Mutation
const original = [1, 2, 3];
const reversed = original.toReversed();
console.log(reversed);  // [3, 2, 1]
console.log(original);  // [1, 2, 3]

Arrays verbinden & teilen

concat / Spread

const arr1 = [1, 2];
const arr2 = [3, 4];
const arr3 = [5, 6];

// concat
const verbunden = arr1.concat(arr2, arr3);
console.log(verbunden);  // [1, 2, 3, 4, 5, 6]

// Spread (moderner)
const verbunden2 = [...arr1, ...arr2, ...arr3];
console.log(verbunden2);  // [1, 2, 3, 4, 5, 6]

slice

const arr = [0, 1, 2, 3, 4, 5];

console.log(arr.slice(2));      // [2, 3, 4, 5] - ab Index 2
console.log(arr.slice(2, 4));   // [2, 3] - Index 2 bis 4 (exklusiv)
console.log(arr.slice(-2));     // [4, 5] - letzte 2
console.log(arr.slice(1, -1));  // [1, 2, 3, 4] - ohne erstes und letztes

flat / flatMap

// Verschachtelte Arrays "platt" machen
const nested = [1, [2, 3], [4, [5, 6]]];

console.log(nested.flat());     // [1, 2, 3, 4, [5, 6]] - 1 Level
console.log(nested.flat(2));    // [1, 2, 3, 4, 5, 6] - 2 Level
console.log(nested.flat(Infinity));  // Komplett flach

// flatMap = map + flat(1)
const sentences = ["Hallo Welt", "Wie geht es"];
const words = sentences.flatMap(s => s.split(" "));
console.log(words);  // ["Hallo", "Welt", "Wie", "geht", "es"]

Arrays zu Strings

const arr = ["Apfel", "Banane", "Orange"];

// join
console.log(arr.join());       // "Apfel,Banane,Orange"
console.log(arr.join(" - "));  // "Apfel - Banane - Orange"
console.log(arr.join(""));     // "ApfelBananeOrange"

// toString
console.log(arr.toString());   // "Apfel,Banane,Orange"

Performance-Tipps

// 1. push ist schneller als unshift
arr.push(x);    // O(1) - schnell
arr.unshift(x); // O(n) - muss alles verschieben

// 2. Länge cachen bei großen Arrays
const len = arr.length;
for (let i = 0; i < len; i++) { }

// 3. Vorbefüllen statt dynamisch wachsen
const arr = new Array(1000);  // Schneller
const arr = [];  // Dann 1000x push - langsamer

// 4. splice vermeiden wenn möglich
// Alternativen: filter, slice, etc.

Zusammenfassung

MethodeMutiert?Beschreibung
push/popEnde hinzufügen/entfernen
unshift/shiftAnfang hinzufügen/entfernen
spliceÜberall ändern
toSplicedsplice ohne Mutation
sort/reverseSortieren/Umdrehen
toSorted/toReversedOhne Mutation
sliceTeil-Array kopieren
concat/spreadArrays verbinden

Übung: Erstelle eine Funktion groupBy(array, key), die ein Array von Objekten nach einem Schlüssel gruppiert. z.B. groupBy(users, "role"){ admin: [...], user: [...] }