Array.prototype.map() erzeugt ein neues Array, indem auf jedes Element des Originals eine Transformations-Funktion angewandt wird. Anders als forEach (das nur einen Side-Effect ausführt) liefert map ein Ergebnis, das man weiterverarbeiten kann. Das Original bleibt unverändertmap ist die wichtigste immutable Array-Operation in JavaScript. In Kombination mit filter und reduce ergibt sich der typische funktionale Pipeline-Stil. Der Callback bekommt (element, index, array) — die zwei zusätzlichen Argumente werden nur bei Bedarf genutzt.

Signatur & Grundform

JavaScript signatur.js
arr.map(callback: (el: T, i: number, arr: T[]) => U, thisArg?): U[]
JavaScript grundform.js
const zahlen = [1, 2, 3, 4];
const verdoppelt = zahlen.map(x => x * 2);

console.log(zahlen);         // [1, 2, 3, 4] — unverändert
console.log(verdoppelt);     // [2, 4, 6, 8]
Output
[ 1, 2, 3, 4 ]
[ 2, 4, 6, 8 ]

map ist eine der ersten Methoden, die jeder JavaScript-Lernende verinnerlicht. Sie steht im Zentrum des funktionalen Stils.

Callback-Argumente: (element, index, array)

Der Callback bekommt drei Argumente — die meisten nutzen nur das erste.

JavaScript callback-args.js
const items = ['a', 'b', 'c'];

// Nur das Element
console.log(items.map(x => x.toUpperCase()));

// Element + Index
console.log(items.map((x, i) => `${i}: ${x}`));

// Alle drei
const annotated = items.map((x, i, arr) => ({
    wert: x,
    index: i,
    isLast: i === arr.length - 1,
}));
console.log(annotated);
Output
[ 'A', 'B', 'C' ]
[ '0: a', '1: b', '2: c' ]
[
  { wert: 'a', index: 0, isLast: false },
  { wert: 'b', index: 1, isLast: false },
  { wert: 'c', index: 2, isLast: true }
]

Object-Transformation

Sehr verbreitet: Objekte auf Untermengen oder neue Strukturen mappen.

JavaScript object-transform.js
const users = [
    { id: 1, name: 'Anna', email: 'anna@x.de' },
    { id: 2, name: 'Bob',  email: 'bob@x.de' },
];

// Namen extrahieren
const namen = users.map(u => u.name);
console.log(namen);

// Object-Shape umbauen
const summary = users.map(u => ({
    label: `${u.name} (#${u.id})`,
    kontakt: u.email,
}));
console.log(summary);
Output
[ 'Anna', 'Bob' ]
[
  { label: 'Anna (#1)', kontakt: 'anna@x.de' },
  { label: 'Bob (#2)', kontakt: 'bob@x.de' }
]

Pipelines mit filter und reduce

Der idiomatische Stil: erst filtern, dann mappen, dann ggf. aggregieren.

JavaScript pipeline.js
const products = [
    { name: 'Buch',   preis: 15,  verfuegbar: true },
    { name: 'Lampe',  preis: 30,  verfuegbar: false },
    { name: 'Stuhl',  preis: 100, verfuegbar: true },
    { name: 'Tisch',  preis: 200, verfuegbar: true },
];

const summeVerfuegbar = products
    .filter(p => p.verfuegbar)
    .map(p => p.preis)
    .reduce((acc, p) => acc + p, 0);

console.log(summeVerfuegbar);  // 15 + 100 + 200 = 315
Output
315

Jede Methode liefert ein neues Array, kettenbar. Performance: drei Iterationen vs. einer mit klassischem for — meistens unerheblich, bei großen Daten messbar.

map vs. forEach

Beide laufen über das Array. Unterschied: map gibt ein neues Array zurück, forEach nicht. Wenn der Rückgabewert gebraucht wird, ist map die richtige Wahl.

JavaScript map-vs-foreach.js
const arr = [1, 2, 3];

// map: liefert neues Array
const a = arr.map(x => x * 2);
console.log(a);              // [2, 4, 6]

// forEach: kein Rückgabewert (undefined)
const b = arr.forEach(x => x * 2);
console.log(b);              // undefined

// Anti-Pattern: forEach mit Push
const c = [];
arr.forEach(x => c.push(x * 2));
console.log(c);              // [2, 4, 6] — funktioniert, aber map ist klarer
Output
[ 2, 4, 6 ]
undefined
[ 2, 4, 6 ]

Wenn der Sinn eine Transformation ist: map. Wenn der Sinn ein Side-Effect ist (Logging, DOM-Manipulation): forEach. Niemals map ohne den Rückgabewert zu nutzen — Linter (ESLint array-callback-return) warnen davor.

flatMap — Map + Flatten in einem Schritt

Wenn der Callback ein Array zurückgibt und das Ergebnis flach werden soll, gibt es seit ES2019 flatMap.

JavaScript flatmap.js
const woerter = ['Hallo Welt', 'wie geht es dir'];

// map: liefert verschachteltes Array
const verschachtelt = woerter.map(s => s.split(' '));
console.log(verschachtelt);  // [['Hallo', 'Welt'], ['wie', 'geht', 'es', 'dir']]

// flatMap: flach
const flach = woerter.flatMap(s => s.split(' '));
console.log(flach);
Output
[ [ 'Hallo', 'Welt' ], [ 'wie', 'geht', 'es', 'dir' ] ]
[ 'Hallo', 'Welt', 'wie', 'geht', 'es', 'dir' ]

Äquivalent zu arr.map(fn).flat(1), aber effizienter (eine Iteration statt zwei).

map mit async — die Promise-Falle

map ist synchron. Wenn der Callback async ist, liefert map ein Array von Promises — keine fertigen Werte.

JavaScript async-falle.js
async function ladeUser(id) {
    return { id, name: `User-${id}` };
}

// FALSCH: liefert Array<Promise>
const arr1 = [1, 2, 3].map(id => ladeUser(id));
console.log(arr1[0]);   // Promise {...}, nicht das User-Objekt

// RICHTIG: Promise.all + map
(async () => {
    const users = await Promise.all([1, 2, 3].map(ladeUser));
    console.log(users);
})();
Output
Promise { { id: 1, name: 'User-1' } }
[
  { id: 1, name: 'User-1' },
  { id: 2, name: 'User-2' },
  { id: 3, name: 'User-3' }
]

Promise.all parallelisiert die Calls. Wenn sequenziell nötig: for-of mit await im Body.

Sparse Arrays — Löcher werden übersprungen

map überspringt Löcher in sparse Arrays — der Callback wird für sie nicht aufgerufen. Die Löcher bleiben im Ergebnis-Array Löcher.

JavaScript sparse.js
const sparse = [1, , 3];
const verdoppelt = sparse.map(x => x * 2);

console.log(verdoppelt);     // [2, <1 empty item>, 6]
console.log(1 in verdoppelt); // false — Loch erhalten
Output
[ 2, <1 empty item>, 6 ]
false

In modernem Code irrelevant, weil sparse Arrays selten sind. Bei Legacy-Code mit new Array(n) aber wichtig zu wissen.

Besonderheiten

map ist immer immutable — das Original wird nie verändert

Anders als sort, reverse, push erzeugt map grundsätzlich ein neues Array. Daher ist es die Standard-Methode für State-Updates in Redux/React.

Callback bekommt drei Argumente: (el, index, array)

Häufig wird nur das erste genutzt. Index ist praktisch für „erstes/letztes Element"-Logik oder für ID-Generierung. Das dritte (array) ist selten relevant.

map mit async Callback liefert Promises, nicht Werte

Klassische Falle: arr.map(async x => await foo(x)) ergibt ein Array von Promises. Für die fertigen Werte: await Promise.all(arr.map(async ...)). Sequenziell: for-of mit await.

map mit Index für ID-Generierung statt manueller for-Schleife

arr.map((x, i) => ({ id: i, value: x })) erzeugt eine Sammlung mit Index-IDs. Lesbarer als eine For-Schleife mit manuellem Push.

Rückgabe undefined aus Callback erzeugt undefined im Ergebnis

[1, 2, 3].map(x => { if (x > 1) return x * 2; }) liefert [undefined, 4, 6] — der erste Eintrag fehlt nicht, er ist undefined. Wer Elemente weglassen will: filter davor oder dahinter.

ESLint array-callback-return warnt, wenn map kein return hat

arr.map(x => { console.log(x); }) ist meist ein Bug — map ohne Rückgabewert ist sinnlos. Linter weisen darauf hin. Wenn nur Side-Effect gemeint: forEach.

flatMap (ES2019) für Map + Flatten in einem Pass

arr.flatMap(fn) ist äquivalent zu arr.map(fn).flat(1), aber effizienter (eine Iteration). Praktisch wenn der Callback ein Array zurückgibt und das Ergebnis flach werden soll.

Performance: einzelne map oft schneller als Pipeline

arr.filter(f1).map(f2).reduce(f3) macht drei Iterationen. Eine kombinierte for-of-Schleife wäre eine. Bei großen Arrays (>100k) messbar, bei normalem Code irrelevant. Lazy-Evaluation via Iterator Helpers (ES2025) löst das systematisch.

Weiterführende Ressourcen

Externe Quellen

/ Weiter

Zurück zu Arrays

Zur Übersicht