ES5.1 以前では key-value の集合である連想配列(ハッシュテーブル)はオブジェクトで表現できて、そのキー全てを配列で得たいときには Object.keys()
を使ってきた。同じことをしたいときに ES2015 の機能を使うとどうやって書き直せるかなと考えた話。
ECMAScript 5.1 で連想配列を表現する
オブジェクトリテラルでオブジェクトを生成して、 foo
・ bar
・ baz
と対になる値を文字列で指定している。キー全てを取得するには、お馴染み Object.keys()
を使うとオブジェクトのキーを配列で取得できる。
var map = {
foo: 'value for foo',
bar: 'value for bar',
baz: 'value for baz'
};
Object.keys(map);
// => ["foo", "bar", "baz"]
for + in
と Object.prototype.hasOwnProperty()
でも目的を達成出来そうだが、 Object.keys()
のほうが簡潔だしスタンダードなやり方かもしれない。
ES2015 で追加された Map
で連想配列を表現する
ES2015 からはグローバルオブジェクトには、連想配列形式のデータを表現するための Map
が追加されているので、それを使うと良い。
let map = new Map([
['foo', 'value for foo'],
['bar', 'value for bar'],
['baz', 'value for baz']
]);
Map
には便利な関数が備わっている他、文字列以外をキーに指定できたり、 Iterable
だったりする。詳しくは Map - JavaScript | MDN を見てもらうと良さそう。
Map
インスタンスのキーを配列で取得する
Map
のインスタンスからキー全てを参照するために、Map.prototype.keys()
という関数が備わっている。しかし、 Map.prototype.keys()
が返すのは Iterable
なオブジェクトなので、 for of
などで列挙したいときには問題ないが配列は得られない。調べてみたところ、こちらも ES2015 から追加された Array.from()
という関数を使うのが一番シンプルっぽい。
Array.from(map);
// => ["foo", "bar", "baz"]
自作ながら Array.ofのポリフィル もある。
Array.from()
に Iterable
なオブジェクトを渡す
Array.from()
は与えられた引数から配列を生成する関数だが、引数には arrayLike なオブジェクト( NodeList とか)の他にも Map.prototype.keys()
が返すような Iterable
なオブジェクトも受け付けている。ので、他の Iterable
なオブジェクト( Set.prototype.entries()
の返り値など)にも応用できる。
let map = new Map();
map.add('key', 'value');
map.add(1, {});
let set = new Set();
set.add(1);
set.add('value');
Array.from(document.querySelectorAll('div'));
Array.from(map.entries());
Array.from(set.values());
Spread オペレータで展開する
Iteration Protocol は Spread オペレータをサポートしているので、 Array.from()
よりシンプルに記述できる。が、先程の例の document.querySelectorAll('div')
の返り値( NodeList
)のような arrayLike なオブジェクトには対応していない。
// Iterable なものは Spread Operator で展開できる
[...map.entries()];
[...set.values()];
// NodeList は展開できない
[...document.querySelectorAll('div')];