プレーンオブジェクトをES6マップに変換する方法は?


128

どういうわけか、MDNのドキュメントでこの単純なものを見つけることができません(たぶん私はそれを逃しているだけです)。

私はこれがうまくいくと思っていました:

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

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

...しかし、最初の行がスローされます TypeError: (var)[Symbol.iterator] is not a function

プレーンオブジェクトからマップを作成するにはどうすればよいですか?本当に最初にそれをキーと値のペアの配列の配列に変換する必要がありますか?


2
FWIW、あなたの受け入れられた答えを私のものからnils 'bergiのものに切り替える価値があるかもしれません。Object.entries実際、はより優れたアプローチでObject.keysあり、bergiのジェネレーター関数アプローチは、Object.keysまたはよりも少し直接的ですObject.entries
TJクラウダー2018

回答:


194

はい、Mapコンストラクタはキーと値のペアの配列を取ります。

Object.entriesES2017(19.1.2.5)で利用可能な新しいオブジェクト静的メソッドです。

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

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

現在、Firefox 46以降、Edge 14以降、およびChromeの新しいバージョンに実装されています

古い環境をサポートする必要があり、トランスパイレーションを選択できない場合は、georgが推奨するようなポリフィルを使用します。

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

3
「ポリフィルは」かなり些細なことになります。Object.entries = obj => Object.keys(obj).map(k => [k, obj[k]])
ゲオルク

4
Object.entriesノード7.x本体(フラグなし)に着陸しました
Lee Benson

2
Node7のObject.entriesだけでなく、ES2017の最終仕様の一部でもあります。したがって、これは受け入れられた答えであるはずです、IMO
AnilRedshift

1
@AnilRedshift-まあ、OP または仲介者を回避するソリューションをOPが求めたため、これまたはジェネレーター関数の答え
TJクラウダー2018

2
残念ながら、そうはなりません。
Nemanja Milosavljevic

78

参照してください使用してNILS'の答えをObject.entries、および/またはbergiの答えはジェネレータ関数を使用してけれどもはObject.entriesスペックではありませんでした、まだ質問が尋ねられたとき、それはステージ4にあった(ただ)2016年4月中にも背中にポリフィル及び使用するので、安全な、。(ここのステージの詳細。)そして、ジェネレーター関数はES2015にありました。OPは特に仲介者を回避するように求め、ジェネレーターはそれを完全には回避しませんが、以下または(わずかに)より優れた働きをしますObject.enties

FWIW、使用Object.entries

  • [name, value]渡す配列の配列を作成しますnew Map
  • Mapコンストラクタは、イテレータを取得するには、アレイ上の関数を呼び出します。配列は配列インターレーターオブジェクトを作成して返します。
  • Mapイテレータオブジェクトはエントリ(取得することをコンストラクタ用途[name, value]配列)とマップを構築

ジェネレーターの使用:

  • ジェネレータ関数を呼び出した結果としてジェネレータオブジェクトを作成します
  • Mapコンストラクタはそれからイテレータを取得することジェネレータオブジェクトに関数を呼び出します。ジェネレータオブジェクトはそれ自体を返します
  • Mapコンストラクタは、エントリ(取得する(イテレータなど)ジェネレータオブジェクトを使用する[name, value]配列)とマップを構築します

したがって、仲介者が1つ少なくなります(からの配列Object.entries)。

ただし、使用する方Object.entriesが簡単で、その配列の作成は99.999%の時間の問題ではありません。だから本当に、どちらか。しかし、どちらも以下よりも優れています。:-)


元の答え:

を初期化するMapには、配列の配列など、キーと値のペアを配列として返す任意のイテレータを使用できます。

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

オブジェクトからマップへの組み込みの変換はありませんが、次のように簡単に実行できますObject.keys

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

もちろん、それを処理するワーカー関数を自分に与えることもできます。

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

その後

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

または、これはよりl33tに見えるバージョンです(それはまだですか?)バージョン:

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

(はい、Map#setマップ参照を返します。これはの乱用だと主張するもいreduceます。)

または、私たちは本当に覆い隠しに乗り越えることができます

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

いいえ、私はそれを実際に行うことはありません。:-)


1
@Oharと@TJCrowderのソリューションの融合:var buildMap2 = o => new Map(Object.keys(o).map(k => [k, o[k]]));
7vujy0f0hy 2017年

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

Object.entries答えが優先されなければならない
キール

@Kir- そうか、ジェネレータか。私の編集を参照してください。
TJクラウダー2018

31

本当に最初にそれをキーと値のペアの配列の配列に変換する必要がありますか?

いいえ、キーと値のペア配列のイテレータで十分です。以下を使用して、中間配列の作成を回避できます。

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

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

良い例-他の人へのメモとしてif(!obj.hasOwnProperties(key)) continue;、オブジェクトのプロトタイプから継承されたプロパティを生成しないように、forループ条件の直後に実行することをお勧めします(オブジェクトを信頼しない限り、これを行うには、in良い習慣として)。
puiu

2
@Puiuいいえ、すべきではありません。悪い習慣です。オブジェクトを信頼しない場合は、その.hasOwnPropertyプロパティも信頼してはならず、使用する必要がありますObject.prototype.hasOwnProperty.call(obj, key)
Bergi

2
はい、私は気にしないことがベストプラクティスだと思います。列挙可能な継承プロパティがないように、列挙する価値のあるすべてのオブジェクト(つまり、キーと値のマップ)を信頼する必要があります。(もちろん、はい、配列の列挙避けてください)。あなたが何か他のものを列挙するまれなケースがあり、あなたが気になるなら、あなたは少なくともで正しくそれをするべきcallです。そこに推奨obj.hasOwnProperties(key)されているすべての規約は、彼らが何をしているのかまったくわからないようです。
Bergi

3
Objectをaに変換するのMapはコストのかかる操作であり、OPは特に中間体なしのソリューションを求めていました。では、なぜこれが例外的な答えではないのですか?まあ、これはおそらく無駄であると尋ねると、それは私を困らせます。

1
@tmvntyタイプを綴る必要があるかもしれませんfunction* entries<T>(obj: T): Generator<readonly [keyof T, T[keyof T]]> {…}。また、yield [key, obj[key]] as const;活字体は、それが配列、タプルを得ないということを実現役立つだろう。
ベルギ

11

Nilsの答えは、オブジェクトをマップに変換する方法を説明ています。ただし、OPはこの情報がMDNドキュメントのどこにあるのかも疑問に思っていました。質問が最初に出されたときはなかったかもしれませんが、現在はObject.entries()の MDNページの見出し「オブジェクトをマップに変換する」の下にあります。

オブジェクトをマップに変換する

new Map()コンストラクタは、反復可能なのを受け入れますentries。を使用するとObject.entries、からObjectに簡単に変換できます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
@Oharと@TJCrowderのソリューションの融合:var buildMap2 = o => new Map(Object.keys(o).map(k => [k, o[k]]));
7vujy0f0hy 2017年

私もオブジェクトキーをソートする必要があったので、ありがとう!
scottwernervt


1

ES6

オブジェクトをマップに変換します。

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

マップをオブジェクトに変換します。

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

注:mapToObj関数は、マップキーが文字列であることを前提としています(それ以外の場合は失敗します)。


-1

いくつかのJQueryの助けを借りて、

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

4
2019年には、問題を解決するためにjqueryを探すべきではないと感じています。
illcrx

jQueryはまだ多くのプロジェクトにあり、これは悪い答えではなく、最適ではありません。
ボートコーダー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.