Start · Sprachen · JavaScript · Referenz · Map

Map

Klasse

Das <code>Map</code>-Objekt speichert Schlüssel-Wert-Paare und merkt sich die ursprüngliche Einfügereihenfolge der Schlüssel.

seit JavaScript ES2015 Kategorie: core

Signatur

new Map() new Map(iterable)

Beschreibung

Map-Objekte sind Sammlungen von Schlüssel-Wert-Paaren. Ein Schlüssel in der Map darf nur einmal vorkommen; er ist innerhalb der Sammlung der Map eindeutig. Ein Map-Objekt wird über Schlüssel-Wert-Paare iteriert — eine for...of-Schleife liefert bei jeder Iteration ein zweigliedriges Array [key, value]. Die Iteration erfolgt in Einfügereihenfolge, welche der Reihenfolge entspricht, in der jedes Schlüssel-Wert-Paar erstmals über die Methode set() in die Map eingefügt wurde (also als noch kein Schlüssel mit demselben Wert in der Map vorhanden war, als set() aufgerufen wurde).

Die Spezifikation verlangt, dass Maps so implementiert werden, „dass sie im Durchschnitt Zugriffszeiten bieten, die sublinear zur Anzahl der Elemente in der Sammlung sind". Daher könnte sie intern als Hashtabelle (mit O(1)-Lookup), als Suchbaum (mit O(log(N))-Lookup) oder als jede andere Datenstruktur dargestellt werden, solange die Komplexität besser als O(N) ist.

Schlüsselgleichheit

Die Wertgleichheit basiert auf dem SameValueZero-Algorithmus. (Früher wurde SameValue verwendet, wodurch 0 und -0 als unterschiedlich behandelt wurden. Siehe Browser-Kompatibilität.) Das bedeutet, dass NaN als gleich mit NaN betrachtet wird (obwohl NaN !== NaN gilt) und alle anderen Werte gemäß der Semantik des ===-Operators als gleich gelten. Für Objekt-Schlüssel basiert die Gleichheit außerdem auf der Objektidentität. Sie werden per Referenz verglichen, nicht per Wert.

Objects vs. Maps

Object ist der Map ähnlich — beide erlauben es, Schlüsseln Werte zuzuweisen, diese Werte abzurufen, Schlüssel zu löschen und zu erkennen, ob etwas unter einem Schlüssel gespeichert ist. Aus diesem Grund (und weil es keine eingebauten Alternativen gab) wurde Object historisch als Map verwendet.

Es gibt jedoch wichtige Unterschiede, die Map in manchen Fällen vorzuziehen machen:

  • Unbeabsichtigte Schlüssel: Eine Map enthält standardmäßig keine Schlüssel. Sie enthält nur, was explizit hineingesteckt wird. Ein Object hat einen prototype, weshalb es Standard-Schlüssel enthält, die mit eigenen Schlüsseln kollidieren können.
  • Sicherheit: Eine Map kann sicher mit vom Benutzer bereitgestellten Schlüsseln und Werten verwendet werden. Das Setzen benutzerdefinierter Schlüssel-Wert-Paare auf einem Object kann es einem Angreifer erlauben, den prototype des Objekts zu überschreiben, was zu Object-Injection- oder Prototype-Pollution-Angriffen führen kann.
  • Schlüsseltypen: Die Schlüssel einer Map können beliebige Werte sein (einschließlich Funktionen, Objekte oder beliebige Primitive). Die Schlüssel eines Object müssen entweder ein String oder ein Symbol sein.
  • Schlüsselreihenfolge: Die Schlüssel in einer Map sind auf klare Weise geordnet: Ein Map-Objekt iteriert Einträge, Schlüssel und Werte in Einfügereihenfolge. Die Reihenfolge in einem gewöhnlichen Object ist zwar mittlerweile definiert, war es aber nicht immer und ist komplex.
  • Größe: Die Anzahl der Elemente in einer Map lässt sich einfach über die Eigenschaft size abrufen. Bei einem Object ist dies umständlicher und weniger effizient.
  • Iteration: Eine Map ist ein iterable und kann direkt iteriert werden. Object implementiert kein iteration protocol, weshalb Objekte standardmäßig nicht direkt mit der for...of-Anweisung iteriert werden können.
  • Performance: Map ist in Szenarien mit häufigem Hinzufügen und Entfernen von Schlüssel-Wert-Paaren leistungsfähiger. Object ist dafür nicht optimiert.
  • Serialisierung und Parsing: Map hat keine native Unterstützung für Serialisierung oder Parsing. Object unterstützt nativ die Serialisierung nach JSON via JSON.stringify() und das Parsen aus JSON via JSON.parse().

Setzen von Objekt-Eigenschaften

Das Setzen von Object-Eigenschaften funktioniert auch bei Map-Objekten und kann zu erheblicher Verwirrung führen. Diese Art, eine Eigenschaft zu setzen, interagiert jedoch nicht mit der Map-Datenstruktur, sondern nutzt das Feature des generischen Objekts. Die korrekte Verwendung zum Speichern von Daten in der Map erfolgt über die Methode set(key, value).

Map-ähnliche Browser-APIs

Browser-Map-ähnliche Objekte (oder „maplike objects") sind Web-API-Schnittstellen, die sich in vielerlei Hinsicht wie eine Map verhalten. Genau wie bei Map können Einträge in derselben Reihenfolge iteriert werden, in der sie dem Objekt hinzugefügt wurden. Map-ähnliche Objekte und Map haben zudem Eigenschaften und Methoden mit demselben Namen und Verhalten. Anders als Map erlauben sie jedoch nur bestimmte, vordefinierte Typen für die Schlüssel und Werte jedes Eintrags.

Map-ähnliche Objekte sind entweder read-only oder read-writable (siehe das Schlüsselwort readonly in der IDL).

Parameter

Name Typ Default Beschreibung
$iterable Iterable<[K, V]>|null|undefined undefined Ein iterierbares Objekt, dessen Elemente [Schlüssel, Wert]-Paare sind (z. B. ein Array von Arrays). Wird null, undefined oder nichts übergeben, startet die Map leer.

Rückgabewert

Typ
Map<K, V>
Beschreibung
Eine neue Map-Instanz, optional bereits mit den angegebenen Schlüssel-Wert-Paaren befüllt.

Beispiele

Verwendung des Map-Objekts

const myMap = new Map();

const keyString = "a string";
const keyObj = {};
const keyFunc = () => {};

// setting the values
myMap.set(keyString, "value associated with 'a string'");
myMap.set(keyObj, "value associated with keyObj");
myMap.set(keyFunc, "value associated with keyFunc");

console.log(myMap.size); // 3

// getting the values
console.log(myMap.get(keyString)); // "value associated with 'a string'"
console.log(myMap.get(keyObj)); // "value associated with keyObj"
console.log(myMap.get(keyFunc)); // "value associated with keyFunc"

console.log(myMap.get("a string")); // "value associated with 'a string'", because keyString === 'a string'
console.log(myMap.get({})); // undefined, because keyObj !== {}
console.log(myMap.get(() => {})); // undefined, because keyFunc !== () => {}

NaN als Map-Schlüssel verwenden

const myMap = new Map();
myMap.set(NaN, "not a number");

myMap.get(NaN);
// "not a number"

const otherNaN = Number("foo");
myMap.get(otherNaN);
// "not a number"

Map mit for...of iterieren

const myMap = new Map();
myMap.set(0, "zero");
myMap.set(1, "one");

for (const [key, value] of myMap) {
  console.log(`${key} = ${value}`);
}
// 0 = zero
// 1 = one

for (const key of myMap.keys()) {
  console.log(key);
}
// 0
// 1

for (const value of myMap.values()) {
  console.log(value);
}
// zero
// one

for (const [key, value] of myMap.entries()) {
  console.log(`${key} = ${value}`);
}
// 0 = zero
// 1 = one

Map mit forEach() iterieren

myMap.forEach((value, key) => {
  console.log(`${key} = ${value}`);
});
// 0 = zero
// 1 = one

Beziehung zu Array-Objekten

const kvArray = [
  ["key1", "value1"],
  ["key2", "value2"],
];

// Use the regular Map constructor to transform a 2D key-value Array into a map
const myMap = new Map(kvArray);

console.log(myMap.get("key1")); // "value1"

// Use Array.from() to transform a map into a 2D key-value Array
console.log(Array.from(myMap)); // Will show you exactly the same Array as kvArray

// A succinct way to do the same, using the spread syntax
console.log([...myMap]);

// Or use the keys() or values() iterators, and convert them to an array
console.log(Array.from(myMap.keys())); // ["key1", "key2"]

Maps klonen und zusammenführen

const original = new Map([[1, "one"]]);

const clone = new Map(original);

console.log(clone.get(1)); // one
console.log(original === clone); // false (useful for shallow comparison)

Maps zusammenführen

const first = new Map([
  [1, "one"],
  [2, "two"],
  [3, "three"],
]);

const second = new Map([
  [1, "uno"],
  [2, "dos"],
]);

// Merge two maps. The last repeated key wins.
// Spread syntax essentially converts a Map to an Array
const merged = new Map([...first, ...second]);

console.log(merged.get(1)); // uno
console.log(merged.get(2)); // dos
console.log(merged.get(3)); // three

Maps mit Arrays zusammenführen

const first = new Map([
  [1, "one"],
  [2, "two"],
  [3, "three"],
]);

const second = new Map([
  [1, "uno"],
  [2, "dos"],
]);

// Merge maps with an array. The last repeated key wins.
const merged = new Map([...first, ...second, [1, "un"]]);

console.log(merged.get(1)); // un
console.log(merged.get(2)); // dos
console.log(merged.get(3)); // three

// Wichtig · Fallstricke

Beim Klonen einer Map werden die Daten selbst nicht kopiert. Es handelt sich lediglich um eine flache Kopie (shallow copy) der Map.

Siehe auch