JavaScript >> Javascript-Tutorial >  >> Tags >> map

ECMAScript 6-Sammlungen, Teil 2:Karten

Karten 1 , wie Mengen, sind auch für diejenigen, die aus anderen Sprachen kommen, ein bekanntes Thema. Die Grundidee besteht darin, einen Wert einem eindeutigen Schlüssel so zuzuordnen, dass Sie diesen Wert jederzeit mithilfe des Schlüssels abrufen können. In JavaScript haben Entwickler traditionell reguläre Objekte als Karten verwendet. Tatsächlich basiert JSON auf der Prämisse, dass Objekte Schlüssel-Wert-Paare darstellen. Die gleiche Einschränkung, die sich auf Objekte auswirkt, die als Sets verwendet werden, betrifft jedoch auch Objekte, die als Maps verwendet werden:die Unfähigkeit, Nicht-String-Schlüssel zu haben.

Vor ECMAScript 6 haben Sie vielleicht Code gesehen, der so aussah:

var map = {};

// later
if (!map[key]) {
    map[key] = value;
}

Dieser Code verwendet ein reguläres Objekt, das sich wie eine Karte verhält und prüft, ob ein bestimmter Schlüssel vorhanden ist. Die größte Einschränkung hier ist key wird immer in einen String umgewandelt. Das ist keine große Sache, bis Sie einen Nicht-String-Wert als Schlüssel verwenden möchten. Vielleicht möchten Sie zum Beispiel einige Daten speichern, die sich auf ein bestimmtes DOM-Element beziehen. Sie könnten Folgendes versuchen:

// element gets converted to a string
var data = {},
    element = document.getElementById("my-div");

data[element] = metadata;

Leider element wird in den String "[Object HTMLDivElement]" umgewandelt oder ähnlich (die genauen Werte können je nach Browser unterschiedlich sein). Das ist problematisch, weil alle <div> -Element wird in dieselbe Zeichenfolge konvertiert, was bedeutet, dass Sie ständig denselben Schlüssel überschreiben, obwohl Sie technisch gesehen verschiedene Elemente verwenden. Aus diesem Grund ist die Map type ist eine willkommene Ergänzung zu JavaScript.

Das ECMAScript 6 Map Typ ist eine geordnete Liste von Schlüssel-Wert-Paaren, wobei sowohl der Schlüssel als auch der Wert von beliebigem Typ sein können. Ein Schlüssel von 5 unterscheidet sich von einem Schlüssel von "5" , und Schlüssel werden anhand derselben Regeln als gleich bestimmt wie Werte für einen Satz:NaN ist dasselbe wie NaN , -0 unterscheidet sich von +0 , andernfalls die === gilt. Mit set() können Sie Daten auf einer Karte speichern und abrufen und get() Methoden:

var map = new Map();
map.set("name", "Nicholas");
map.set(document.getElementById("my-div"), { flagged: false });

// later
var name = map.get("name"),
    meta = map.get(document.getElementById("my-div"));

In diesem Beispiel werden zwei Schlüssel-Wert-Paare gespeichert. Der Schlüssel "name" speichert einen String während der Schlüssel document.getElementById("my-div") wird verwendet, um Metadaten mit einem DOM-Element zu verknüpfen. Wenn der Schlüssel nicht in der Map vorhanden ist, dann der Sonderwert undefined wird beim Aufruf von get() zurückgegeben .

Maps teilte einige Methoden mit Sets, wie z. B. has() um festzustellen, ob ein Schlüssel in der Karte vorhanden ist, und delete() zum Entfernen eines Schlüssel-Wert-Paares aus der Map. Sie können auch size verwenden So ermitteln Sie, wie viele Elemente sich auf der Karte befinden:

var map = new Map();
map.set("name", "Nicholas");

console.log(map.has("name"));   // true
console.log(map.get("name"));   // "Nicholas"
console.log(map.size);        // 1

map.delete("name");
console.log(map.has("name"));   // false
console.log(map.get("name"));   // undefined
console.log(map.size);        // 0

Wenn Sie alle Elemente von der Karte entfernen möchten, können Sie den clear() verwenden Methode:

var map = new Map();
map.set("name", "Nicholas");

console.log(map.has("name"));   // true
console.log(map.get("name"));   // "Nicholas"
console.log(map.size);        // 1

map.clear();
console.log(map.has("name"));   // false
console.log(map.get("name"));   // undefined
console.log(map.size);        // 0

Um das Hinzufügen großer Datenmengen zu einer Karte zu vereinfachen, können Sie ein Array von Arrays an Map übergeben Konstrukteur. Intern wird jedes Schlüssel-Wert-Paar als Array mit zwei Elementen gespeichert, wobei das erste der Schlüssel und das zweite der Wert ist. Die gesamte Map ist daher ein Array dieser Arrays mit zwei Elementen, und Maps können daher mit diesem Format initialisiert werden:

var map = new Map([ ["name", "Nicholas"], ["title", "Author"]]);

console.log(map.has("name"));   // true
console.log(map.get("name"));   // "Nicholas"
console.log(map.has("title"));  // true
console.log(map.get("title"));  // "Author"
console.log(map.size);        // 2

Wenn Sie mit allen Daten in der Karte arbeiten möchten, haben Sie mehrere Möglichkeiten. Es stehen tatsächlich drei Generatormethoden zur Auswahl:keys , das über die Schlüssel in der Karte iteriert, values , das über die Werte in der Karte iteriert, und items , das über Schlüssel-Wert-Paare iteriert, indem es ein Array zurückgibt, das den Schlüssel und den Wert enthält (items ist der Standard-Iterator für Karten). Der einfachste Weg, diese zu nutzen, ist die Verwendung eines for-of Schleife:

for (let key of map.keys()) {
    console.log("Key: %s", key);
}

for (let value of map.values()) {
    console.log("Value: %s", value);
}

for (let item of map.items()) {
    console.log("Key: %s, Value: %s", item[0], item[1]);
}

// same as using map.items()
for (let item of map) {
    console.log("Key: %s, Value: %s", item[0], item[1]);
}

Wenn Sie über Schlüssel oder Werte iterieren, erhalten Sie jedes Mal einen einzelnen Wert durch die Schleife. Beim Iterieren über Elemente erhalten Sie ein Array, dessen erstes Element der Schlüssel und das zweite Element der Wert ist.

Eine andere Möglichkeit, Elemente zu durchlaufen, ist die Verwendung von forEach() Methode. Diese Methode funktioniert ähnlich wie forEach() auf Arrays. Sie übergeben eine Funktion, die mit drei Argumenten aufgerufen wird:dem Wert, dem Schlüssel und der Map selbst. Zum Beispiel:

map.forEach(function(value, key, map)) {
    console.log("Key: %s, Value: %s", key, value);
});

Auch ähnlich der Arrays-Version von forEach() , können Sie ein optionales zweites Argument übergeben, um den this anzugeben Wert, der im Callback verwendet werden soll:

var reporter = {
    report: function(key, value) {
        console.log("Key: %s, Value: %s", key, value);
    }
};

map.forEach(function(value, key, map) {
    this.report(key, value);
}, reporter);

Hier der this Wert innerhalb der Callback-Funktion ist gleich reporter . Das erlaubt this.report() richtig funktionieren.

Vergleichen Sie dies mit der umständlichen Art, Werte und ein reguläres Objekt zu durchlaufen:

for (let key in object) {

    // make sure it's not from the prototype!
    if (object.hasOwnProperty(key)) {
        console.log("Key: %s, Value: %s", key, object[key]);
    }

}

Bei der Verwendung von Objekten als Maps gab es immer Bedenken, dass Eigenschaften aus dem Prototyp in einer „for-in“-Schleife durchsickern könnten. Sie müssen immer `hasOwnProperty()` verwenden, um sicherzugehen, dass Sie nur die gewünschten Eigenschaften erhalten. Wenn es Methoden für das Objekt gäbe, müssten Sie diese natürlich auch filtern:

for (let key in object) {

    // make sure it's not from the prototype or a function!
    if (object.hasOwnProperty(key) &#038;&#038; typeof object[key] !== "function") {
        console.log("Key: %s, Value: %s", key, object[key]);
    }

}

Die Iterationsfunktionen von Karten ermöglichen es Ihnen, sich nur auf die Daten zu konzentrieren, ohne sich Sorgen machen zu müssen, dass zusätzliche Informationen in Ihren Code gelangen. Dies ist ein weiterer großer Vorteil von Maps gegenüber regulären Objekten zum Speichern von Schlüssel-Wert-Paaren.

Browser-Unterstützung

Sowohl Firefox als auch Chrome haben Map implementiert , in Chrome müssen Sie die ECMAScript 6-Funktionen jedoch manuell aktivieren:Gehen Sie zu chrome://flags und aktivieren Sie „Experimentelle JavaScript-Funktionen“. Beide Implementierungen sind unvollständig. Keiner der Browser implementiert eine der Generatormethoden zur Verwendung mit for-of und in der Chrome-Implementierung fehlt der size() -Methode (die Teil der ECMAScript 6-Entwurfsspezifikation 2 ist ) und der Konstruktor führt keine Initialisierung durch, wenn ein Array von Arrays übergeben wird.

Zusammenfassung

ECMAScript 6-Maps bringen ein sehr wichtiges und häufig verwendetes Feature in die Sprache. Entwickler wollten schon lange eine zuverlässige Methode zum Speichern von Schlüssel-Wert-Paaren und haben sich viel zu lange auf reguläre Objekte verlassen. Maps Bieten alle Fähigkeiten, die normale Objekte nicht haben, einschließlich einfacher Möglichkeiten, über Schlüssel und Werte zu iterieren und Bedenken hinsichtlich Prototypen zu beseitigen.

Karten sind wie Sets Teil des ECMAScript 6-Entwurfs, der noch nicht vollständig ist. Aus diesem Grund gelten Karten immer noch als experimentelle API und können sich ändern, bevor die Spezifikation abgeschlossen ist. Alle Beiträge zu ECMAScript 6 sollten als Vorschau auf das, was kommt, und nicht als endgültige Referenzen betrachtet werden. Obwohl die experimentellen APIs in einigen Browsern implementiert sind, können sie noch nicht in der Produktion verwendet werden.

Aktualisierungen

  • 05. Januar 2014 – Verweis auf size() geändert Methode zu size -Eigenschaft, um Änderungen in der Spezifikation widerzuspiegeln.

Referenzen

  1. Einfache Karten und Sets (ES6-Wiki)
  2. ECMAScript 6-Spezifikationsentwurf (ECMA)