Wie konvertiere ich ein einfaches Objekt in eine ES6-Karte?


125

Aus irgendeinem Grund kann ich diese einfache Sache nicht in den MDN-Dokumenten finden (vielleicht fehlt sie mir nur).

Ich habe erwartet, dass das funktioniert:

const map = new Map({foo: 'bar'});

map.get('foo'); // 'bar'

... aber die erste Zeile wirft TypeError: (var)[Symbol.iterator] is not a function

Wie erstelle ich eine Karte aus einem einfachen Objekt? Muss ich es wirklich zuerst in ein Array von Arrays von Schlüssel-Wert-Paaren konvertieren?


2
FWIW, kann es sich lohnen Schalt Ihre akzeptierte Antwort sein Mine zu nils' oder bergi ist . Object.entrieswirklich ist der bessere Ansatz vorbei Object.keys, und Bergis Generatorfunktionsansatz ist etwas direkter als entweder Object.keysoder Object.entries.
TJ Crowder

Antworten:


193

Ja, der MapKonstruktor verwendet ein Array von Schlüssel-Wert-Paaren.

Object.entriesist eine neue statische Objektmethode, die in ES2017 (19.1.2.5) verfügbar ist .

const map = new Map(Object.entries({foo: 'bar'}));

map.get('foo'); // 'bar'

Es ist derzeit in Firefox 46+ und Edge 14+ sowie in neueren Versionen von Chrome implementiert

Wenn Sie ältere Umgebungen unterstützen müssen und Transpilation für Sie keine Option ist, verwenden Sie eine Polyfüllung, wie die von Georg empfohlene:

Object.entries = typeof Object.entries === 'function' ? Object.entries : obj => Object.keys(obj).map(k => [k, obj[k]]);

3
Eine "Polyfüllung" wird eher trivial sein:Object.entries = obj => Object.keys(obj).map(k => [k, obj[k]])
Georg

4
Object.entrieslandete in Node 7.x (ohne Flagge) übrigens
Lee Benson

2
Object.entries befindet sich nicht nur in Node7, sondern ist auch Teil der endgültigen ES2017-Spezifikation. Daher sollte dies die akzeptierte Antwort sein, IMO
AnilRedshift

1
Wird dadurch eine Schlüsselbestellung erhalten oder erzwungen?
Backdesk

2
Leider wird es nicht.
Nemanja Milosavljevic

78

Bitte sehen Sie die Antwort von nils mitObject.entries und / oder die Antwort von bergi mit einer Generatorfunktion . Obwohl Object.entrieses noch nicht in der Spezifikation enthalten war, als die Frage gestellt wurde, befand es sich in Phase 4 , so dass es bereits im April 2016 (nur) sicher gefüllt und verwendet werden konnte. (Mehr zu den Stufen hier .) Und Generatorfunktionen waren in ES2015. Das OP hat ausdrücklich darum gebeten, Vermittler zu vermeiden, und obwohl der Generator dies nicht vollständig vermeidet, leistet er einen besseren Job als der unten stehende oder (geringfügig) Object.enties.

FWIW, mit Object.entries:

  • Erstellt ein Array von [name, value]Arrays, an die übergeben werden sollnew Map
  • Der MapKonstruktor ruft eine Funktion für das Array auf, um einen Iterator abzurufen. Das Array erstellt ein Array-Interatorobjekt und gibt es zurück.
  • Der MapKonstruktor verwendet dieses Iteratorobjekt, um die Einträge (die [name, value]Arrays) abzurufen und die Karte zu erstellen

Verwenden des Generators:

  • Erstellt ein Generatorobjekt als Ergebnis des Aufrufs der Generatorfunktion
  • Der MapKonstruktor ruft eine Funktion für dieses Generatorobjekt auf, um einen Iterator daraus abzurufen. Das Generatorobjekt gibt sich selbst zurück
  • Der MapKonstruktor verwendet das Generatorobjekt (als Iterator), um die Einträge (die [name, value]Arrays) abzurufen und die Karte zu erstellen

Also: Ein Vermittler weniger (das Array von Object.entries).

Die Verwendung Object.entriesist jedoch einfacher und das Erstellen dieses Arrays ist in 99,999% der Fälle kein Problem. Also wirklich, einer von beiden. Aber sie sind beide besser als die folgenden. :-)


Ursprüngliche Antwort:

Zum Initialisieren von a Mapkönnen Sie einen beliebigen Iterator verwenden, der Schlüssel / Wert-Paare als Arrays zurückgibt, z. B. ein Array von Arrays:

const map = new Map([
    ['foo', 'bar']
]);

Es gibt keine integrierte Konvertierung von Objekt zu Karte, aber es ist einfach mit Object.keys:

const map = new Map();
let obj = {foo: 'bar'};
Object.keys(obj).forEach(key => {
    map.set(key, obj[key]);
});

Sie können sich natürlich eine Arbeiterfunktion geben, um das zu erledigen:

function buildMap(obj) {
    let map = new Map();
    Object.keys(obj).forEach(key => {
        map.set(key, obj[key]);
    });
    return map;
}

Dann

const map = buildMap({foo: 'bar'});

Oder hier ist eine l33t aussehende (ist das noch eine Sache?) Version:

function buildMap(obj) {
    return Object.keys(obj).reduce((map, key) => map.set(key, obj[key]), new Map());
}

(Ja, Map#setgibt die Kartenreferenz zurück. Einige würden argumentieren, dass dies ein Missbrauch von ist reduce.)

Oder wir können die Dunkelheit wirklich übertreiben:

const buildMap = o => Object.keys(o).reduce((m, k) => m.set(k, o[k]), new Map());

Nein, das würde ich nie wirklich tun. :-)


1
Fusion der Lösungen von @ Ohar und @ TJCrowder : var buildMap2 = o => new Map(Object.keys(o).map(k => [k, o[k]]));.
7vujy0f0hy

17
Siehe new Map(Object.entries(object)) stackoverflow.com/a/36644558/798133
Rafael Xavier

Die Antworten von Object.entries sollten bevorzugt werden
Kir

@Kir - Das oder der Generator , ja. Siehe meine Bearbeitung.
TJ Crowder

31

Muss ich es wirklich zuerst in ein Array von Arrays von Schlüssel-Wert-Paaren konvertieren?

Nein, ein Iterator von Schlüssel-Wert-Paar-Arrays reicht aus. Sie können Folgendes verwenden, um das Erstellen des Zwischenarrays zu vermeiden:

function* entries(obj) {
    for (let key in obj)
        yield [key, obj[key]];
}

const map = new Map(entries({foo: 'bar'}));
map.get('foo'); // 'bar'

Nettes Beispiel - nur ein Hinweis für andere. Möglicherweise möchten Sie if(!obj.hasOwnProperties(key)) continue;direkt nach der for-Schleifenbedingung ein Zeichen setzen, um sicherzustellen, dass Sie keine vom Objektprototyp geerbten Eigenschaften erhalten (es sei denn, Sie vertrauen dem Objekt, sollten dies jedoch trotzdem tun, wenn Sie Objekte mit iterieren inals gute Angewohnheit).
Puiu

2
@Puiu Nein, das solltest du nicht und es ist eine schlechte Angewohnheit. Wenn Sie dem Objekt nicht vertrauen, dürfen Sie auch seinem .hasOwnPropertyEigentum nicht vertrauen , und Sie Object.prototype.hasOwnProperty.call(obj, key)
müssten

@Bergi das ist ein guter Punkt, es könnte sein, dass das Objekt hasOwnPropertyauch überschrieben wurde. Wollen Sie damit sagen, dass es eine gute Praxis ist, sich nicht mit der Überprüfung zu beschäftigen? Nur neugierig, alle Konventionen da draußen sagen zu überprüfen oder sie schlagen vor, die Verwendung für ... auf jeden Fall zu vermeiden. Ich würde gerne Ihre Gedanken dazu hören.
Puiu

2
Ja, ich denke, nicht zu stören ist die beste Praxis. Sie sollten darauf vertrauen, dass alle Objekte, die es wert sind, aufgelistet zu werden (dh Schlüsselwertzuordnungen), keine aufzählbaren geerbten Eigenschaften haben. (Und ja, natürlich vermeiden Sie das Aufzählen von Arrays ). Wenn Sie in seltenen Fällen etwas anderes aufzählen und sich die Mühe machen, sollten Sie es zumindest richtig machen call. Alle Konventionen, die es empfehlen, obj.hasOwnProperties(key)scheinen keine Ahnung zu haben, was sie tun.
Bergi

2
Die Umwandlung Objectin eine Mapist eine teure Operation, und das OP hat speziell nach einer Lösung ohne Zwischenprodukte gefragt. Warum ist das nicht die ausgenommene Antwort? Nun, das zu fragen ist wahrscheinlich zwecklos, es nervt mich nur.

11

Die Antwort von Nils beschreibt, wie man Objekte in Karten konvertiert, was ich sehr nützlich fand. Das OP fragte sich jedoch auch, wo sich diese Informationen in den MDN-Dokumenten befinden. Während es möglicherweise nicht vorhanden war, als die Frage ursprünglich gestellt wurde, befindet es sich jetzt auf der MDN-Seite für Object.entries () unter der Überschrift Konvertieren eines Objekts in eine Karte mit folgenden Angaben :

Konvertieren eines Objekts in eine Karte

Der new Map()Konstruktor akzeptiert eine Iterable von entries. Mit Object.entrieskönnen Sie ganz einfach konvertieren von Objectzu Map:

const obj = { foo: 'bar', baz: 42 }; 
const map = new Map(Object.entries(obj));
console.log(map); // Map { foo: "bar", baz: 42 }

7
const myMap = new Map(
    Object
        .keys(myObj)
        .map(
            key => [key, myObj[key]]
        )
)

1
Fusion der Lösungen von @ Ohar und @ TJCrowder : var buildMap2 = o => new Map(Object.keys(o).map(k => [k, o[k]]));.
7vujy0f0hy

Danke, da ich auch die Objektschlüssel sortieren musste!
Scottwernervt


0

ES6

Objekt in Karte konvertieren:

const objToMap = (o) => new Map(Object.entries(o));

Karte in Objekt konvertieren:

const mapToObj = (m) => [...m].reduce( (o,v)=>{ o[v[0]] = v[1]; return o; },{} )

Hinweis: Die Funktion mapToObj geht davon aus, dass Map-Schlüssel Zeichenfolgen sind (andernfalls schlägt dies fehl).


-1

Mit Hilfe von JQuery,

const myMap = new Map();
$.each( obj, function( key, value ) {
myMap[key] = value;
});

3
Ich denke, wir sollten 2019 nicht nach Fragen suchen, um Probleme zu lösen.
illcrx

jQuery ist noch in vielen Projekten und dies ist keine schlechte Antwort, nur nicht optimal.
Bootscodierer
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.