Map

Baseline Widely available

This feature is well established and works across many devices and browser versions. It’s been available across browsers since July 2015.

Das Map Objekt speichert Schlüssel-Werte-Paare und merkt sich die ursprüngliche Einfügereihenfolge der Schlüssel. Jeder Wert (sowohl Objekte als auch primitive Werte) kann sowohl als Schlüssel als auch als Wert verwendet werden.

Probieren Sie es aus

Beschreibung

Map Objekte sind Sammlungen von Schlüssel-Wert-Paaren. Ein Schlüssel in der Map darf nur einmal auftreten; er ist einzigartig in der Sammlung der Map. Ein Map Objekt wird durch Schlüssel-Wert-Paare iteriert — eine for...of Schleife gibt ein Array mit zwei Elementen [key, value] für jede Iteration zurück. Die Iteration erfolgt in der Einfügereihenfolge, die der Reihenfolge entspricht, in der jedes Schlüssel-Wert-Paar zuerst in die Map durch die set() Methode eingefügt wurde (das heißt, es gab keinen Schlüssel mit demselben Wert, als set() aufgerufen wurde).

Die Spezifikation erfordert, dass Maps "so implementiert werden, dass Zugriffzeiten im Durchschnitt sublinear zur Anzahl der Elemente in der Sammlung bieten". Daher könnte es intern als eine Hashtabelle (mit O(1) Zugriff), ein Suchbaum (mit O(log(N)) Zugriff) oder jede andere Datenstruktur dargestellt werden, solange die Komplexität besser als O(N) ist.

Schlüsselgleichheit

Die Gleichheit der Werte basiert auf dem SameValueZero Algorithmus. (Früher wurde SameValue verwendet, das 0 und -0 als unterschiedlich behandelte. Überprüfen Sie die Browser-Kompatibilität.) Dies bedeutet, dass NaN als gleich zu NaN betrachtet wird (auch wenn NaN !== NaN) und alle anderen Werte entsprechend den semantiken des === Operators als gleich gelten.

Objekte vs. Maps

Object ist ähnlich wie Map — beide ermöglichen es Ihnen, Schlüssel auf Werte zu setzen, diese Werte abzurufen, Schlüssel zu löschen und zu erkennen, ob etwas an einem Schlüssel gespeichert ist. Aus diesem Grund (und weil es keine integrierten Alternativen gab), wurde Object historisch als Map verwendet.

Jedoch gibt es wichtige Unterschiede, die Map in einigen Fällen bevorzugt machen:

Map Objekt
Zufällige Schlüssel Eine Map enthält standardmäßig keine Schlüssel. Sie enthält nur das, was explizit hineingelegt wurde.

Ein Objekt hat ein Prototyp, sodass es Standardschlüssel enthält, die mit Ihren eigenen Schlüsseln kollidieren könnten, wenn Sie nicht vorsichtig sind.

Hinweis: Dies kann umgangen werden, indem Object.create(null) verwendet wird, aber das wird selten gemacht.

Sicherheit Eine Map ist sicher in der Verwendung mit benutzerdefinierten Schlüsseln und Werten.

Das Setzen von benutzerdefinierten Schlüssel-Wert-Paaren auf einem Objekt kann es einem Angreifer ermöglichen, das Prototyp des Objekts zu überschreiben, was zu Objekt-Injektionsangriffen führen kann. Wie das Problem mit den zufälligen Schlüsseln, kann dies auch durch die Verwendung eines null-Prototyp-Objekts gemildert werden.

Schlüsseltypen Eine Map's Schlüssel können beliebige Werte sein (einschließlich Funktionen, Objekte oder irgendein primitiver Wert). Die Schlüssel eines Objekts müssen entweder ein String oder ein Symbol sein.
Schlüsselreihenfolge

Die Schlüssel in Map sind in einer unkomplizierten Weise geordnet: Ein Map Objekt iteriert Einträge, Schlüssel und Werte in der Reihenfolge der Einfügung.

Obwohl die Schlüssel eines gewöhnlichen Objekts jetzt geordnet sind, war dies nicht immer der Fall, und die Ordnung ist komplex. Deshalb ist es am besten, sich nicht auf die Reihenfolge der Eigenschaften zu verlassen.

Die Ordnung wurde zuerst nur für eigene Eigenschaften in ECMAScript 2015 definiert; ECMAScript 2020 definiert die Ordnung auch für geerbte Eigenschaften. Aber beachten Sie, dass kein einziges Mechanismus alle Eigenschaften eines Objekts durchläuft; die verschiedenen Mechanismen umfassen jeweils unterschiedliche Untergruppen von Eigenschaften. (for-in umfasst nur aufzählbare string-keyed Eigenschaften; Object.keys umfasst nur eigene, aufzählbare, string-keyed Eigenschaften; Object.getOwnPropertyNames umfasst eigene, string-keyed Eigenschaften, auch wenn sie nicht aufzählbar sind; Object.getOwnPropertySymbols macht dasselbe nur für Symbol-keyed Eigenschaften, etc.)

Größe

Die Anzahl der Elemente in einer Map ist leicht aus ihrer Größe Eigenschaft abzurufen. Das Bestimmen der Anzahl der Elemente in einem Objekt ist umständlicher und weniger effizient. Ein üblicher Weg dies zu tun ist durch die Länge des Arrays, das von Object.keys() zurückgegeben wird.
Iteration Eine Map ist ein iterable, sodass sie direkt iteriert werden kann.

Objekt implementiert kein Iterationsprotokoll, und so sind Objekte nicht direkt iterierbar unter Verwendung des JavaScript for...of Statements (standardmäßig).

Hinweis:

  • Ein Objekt kann das Iterationsprotokoll implementieren, oder Sie können ein iterable für ein Objekt erhalten, indem Sie Object.keys oder Object.entries verwenden.
  • Die for...in Anweisung erlaubt Ihnen, über die aufzählbaren Eigenschaften eines Objekts zu iterieren.
Leistung

Bietet bessere Leistung in Szenarien mit häufigen Hinzufügungen und Entfernungen von Schlüssel-Wert-Paaren.

Nicht optimiert für häufige Hinzufügungen und Entfernungen von Schlüssel-Wert-Paaren.

Serialisierung und Parsen

Keine native Unterstützung für Serialisierung oder Parsen.

(Aber Sie können Ihre eigene Unterstützung für Serialisierung und Parsen für Map aufbauen, indem Sie JSON.stringify() mit seinem replacer-Argument verwenden, und JSON.parse() mit seinem reviver-Argument verwenden. Siehe die Stack Overflow-Frage Wie JSON.stringify ich eine ES6-Map?).

Native Unterstützung für die Serialisierung von Object zu JSON, unter Verwendung von JSON.stringify().

Native Unterstützung für das Parsen von JSON zu Object, unter Verwendung von JSON.parse().

Setzen von Objekteigenschaften

Das Setzen von Objekteigenschaften funktioniert auch für Map-Objekte und kann erhebliche Verwirrung stiften.

Daher scheint es auf diese Weise zu funktionieren:

js
const wrongMap = new Map();
wrongMap["bla"] = "blaa";
wrongMap["bla2"] = "blaaa2";

console.log(wrongMap); // Map { bla: 'blaa', bla2: 'blaaa2' }

Aber diese Art der Eigenschaftszuteilung interagiert nicht mit der Datenstruktur von Map. Es nutzt die Funktionalität eines generischen Objekts. Der Wert von 'bla' wird nicht in der Map für Abfragen gespeichert. Andere Operationen auf den Daten schlagen fehl:

js
wrongMap.has("bla"); // false
wrongMap.delete("bla"); // false
console.log(wrongMap); // Map { bla: 'blaa', bla2: 'blaaa2' }

Die korrekte Verwendung zum Speichern von Daten in der Map ist die Methode set(key, value).

js
const contacts = new Map();
contacts.set("Jessie", { phone: "213-555-1234", address: "123 N 1st Ave" });
contacts.has("Jessie"); // true
contacts.get("Hilary"); // undefined
contacts.set("Hilary", { phone: "617-555-4321", address: "321 S 2nd St" });
contacts.get("Jessie"); // {phone: "213-555-1234", address: "123 N 1st Ave"}
contacts.delete("Raymond"); // false
contacts.delete("Jessie"); // true
console.log(contacts.size); // 1

Map-ähnliche Browser-APIs

Browser Map-ähnliche Objekte (oder "mapähnliche Objekte") sind Web API Schnittstellen, die sich in vielerlei Hinsicht wie eine Map verhalten.

Ähnlich wie Map können Einträge in der gleichen Reihenfolge durchlaufen werden, in der sie zum Objekt hinzugefügt wurden. Map-ähnliche Objekte und Map haben auch Eigenschaften und Methoden, die denselben Namen und dasselbe Verhalten haben. Im Gegensatz zu Map erlauben sie jedoch nur bestimmte vordefinierte Typen für die Schlüssel und Werte jedes Eintrags.

Die erlaubten Typen sind in der Spezifikation IDL-Definition festgelegt. Zum Beispiel muss RTCStatsReport, ein Map-ähnliches Objekt, Zeichenfolgen für Schlüssel und Objekte für Werte verwenden. Dies ist in der Spezifikation IDL unten definiert:

webidl
interface RTCStatsReport {
  readonly maplike<DOMString, object>;
};

Map-ähnliche Objekte sind entweder schreibgeschützt oder schreibbar (siehe das readonly Schlüsselwort im obigen IDL).

Die Methoden und Eigenschaften haben dasselbe Verhalten wie die entsprechenden Entitäten in Map, mit Ausnahme der Einschränkung der Typen für die Schlüssel und Werte.

Die folgenden sind Beispiele für schreibgeschützte Map-ähnliche Browserobjekte:

Konstruktor

Map()

Erstellt ein neues Map Objekt.

Statische Eigenschaften

Map[Symbol.species]

Die Konstruktorfunktion, die verwendet wird, um abgeleitete Objekte zu erstellen.

Statische Methoden

Map.groupBy()

Gruppiert die Elemente eines gegebenen Iterables unter Verwendung der Werte, die von einer bereitgestellten Callback-Funktion zurückgegeben werden. Die endgültig zurückgegebene Map verwendet die einzigartigen Werte aus der Testfunktion als Schlüssel, die verwendet werden können, um das Array von Elementen in jeder Gruppe zu erhalten.

Instanz-Eigenschaften

Diese Eigenschaften sind auf Map.prototype definiert und werden von allen Map Instanzen geteilt.

Map.prototype.constructor

Die Konstruktorfunktion, die das Instanzobjekt erstellt hat. Für Map Instanzen ist der Anfangswert der Map Konstruktor.

Map.prototype.size

Gibt die Anzahl der Schlüssel/Werte-Paare im Map Objekt zurück.

Map.prototype[Symbol.toStringTag]

Der Anfangswert der [Symbol.toStringTag] Eigenschaft ist die Zeichenfolge "Map". Diese Eigenschaft wird in Object.prototype.toString() verwendet.

Instanz-Methoden

Map.prototype.clear()

Entfernt alle Schlüssel-Werte-Paare aus dem Map Objekt.

Map.prototype.delete()

Gibt true zurück, wenn ein Element im Map Objekt existierte und entfernt wurde, oder false, wenn das Element nicht existiert. map.has(key) wird danach false zurückgeben.

Map.prototype.entries()

Gibt ein neues Iterator-Objekt zurück, das ein Array mit zwei Mitgliedern [key, value] für jedes Element im Map Objekt in Einfügereihenfolge enthält.

Map.prototype.forEach()

Ruft callbackFn einmal für jedes Schlüssel-Wert-Paar im Map Objekt in Einfügereihenfolge auf. Wenn ein thisArg Parameter an forEach übergeben wird, wird er als this Wert für jeden Callback verwendet.

Map.prototype.get()

Gibt den Wert zurück, der dem übergebenen Schlüssel zugeordnet ist, oder undefined, wenn keiner vorhanden ist.

Map.prototype.has()

Gibt einen Boolean zurück, der anzeigt, ob ein Wert mit dem übergebenen Schlüssel im Map Objekt verknüpft ist oder nicht.

Map.prototype.keys()

Gibt ein neues Iterator-Objekt zurück, das die Schlüssel für jedes Element im Map Objekt in Einfügereihenfolge enthält.

Map.prototype.set()

Legt den Wert für den übergebenen Schlüssel im Map Objekt fest. Gibt das Map Objekt zurück.

Map.prototype.values()

Gibt ein neues Iterator-Objekt zurück, das die Werte für jedes Element im Map Objekt in Einfügereihenfolge enthält.

Map.prototype[Symbol.iterator]()

Gibt ein neues Iterator-Objekt zurück, das ein Array mit zwei Mitgliedern [key, value] für jedes Element im Map Objekt in Einfügereihenfolge enthält.

Beispiele

Verwendung des Map-Objekts

js
const myMap = new Map();

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

// 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(function () {})); // undefined, because keyFunc !== function () {}

Verwendung von NaN als Map-Schlüssel

NaN kann auch als Schlüssel verwendet werden. Obwohl jedes NaN nicht gleich sich selbst ist (NaN !== NaN ist wahr), funktioniert das folgende Beispiel, weil NaNs ununterscheidbar voneinander sind:

js
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"

Iterieren von Map mit for...of

Maps können mit einer for...of Schleife iteriert werden:

js
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

Iterieren von Map mit forEach()

Maps können mit der forEach() Methode iteriert werden:

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

Beziehung zu Array-Objekten

js
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"]

Klonen und Mischen von Maps

Genau wie Arrays, können Maps geklont werden:

js
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)

Hinweis: Beachten Sie, dass die Daten selbst nicht geklont werden.

Maps können zusammengeführt werden und wahren dabei die Eindeutigkeit der Schlüssel:

js
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 können auch mit Arrays zusammengeführt werden:

js
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

Spezifikationen

Specification
ECMAScript Language Specification
# sec-map-objects

Browser-Kompatibilität

BCD tables only load in the browser

Siehe auch