2014/09/25更新

[JavaScript] ECMAScript6のMapとSetを使ってみよう

このエントリーをはてなブックマークに追加      

こんにちは、@yoheiMuneです。
今日は、ECMAScript6で定義されているMapSetを使ってみたいともいます。Chromeはver.38から使えるので、すぐそこまできている技術です。

画像

Special Thanks to https://flic.kr/p/aBtMu5



目次




Map

多くのプログラミング言語でサポートされているMapが、とうとうJavaScriptでも使えるようになりました。 Mapはコレクション型の1つで、データを格納するためのデータ構造です。 JavaScriptではオブジェクトリテラルを用いて、以下のようにデータを保持することができます。
var data = {
    name: 'Yohei',
    sex: 'male',
    contry: 'JP'
};
Mapでも似たようにKey-Value構造でデータを格納することができます。
// Mapオブジェクトの作成
var map = new Map([
    ['one', 'My key is a string.'],
    ['1', 'My key is also a string'],
    [1, 'My key is a number'],
    [document.querySelector('#log'), 'My key is an object']
]);
そして上記を見ると分かる通り、Keyには文字列以外にも数値やオブジェクトなどを指定することができます。 これは小さなことのように見えますが、かゆいところに手が届く感じで、ありがたい機能です。

Mapの機能をさらっと確認しましょう。以下のようなコードを利用することができます。
// Mapの生成(初期値なし)
var map = new Map();

// Mapの生成(初期値あり)
// 2次元配列で値を指定するんですね...
var map = new Map([
    ['one', 'My key is a string.'],
    [1, 'My key is a number']
]);

// 値の取得
map.get('one'); // => "My key is a string."

// 値の設定
map.set('two', 'aaa');

// 値の設定(キーが同じものは上書きされます)
map.set('two', 'aaa');
map.set('two', 'bbb');
map.get('two'); // =>bbb

// 格納したデータ数
map.size; // => 3

// 存在確認
map.has('one'); // => true

// データの削除(1つ)
map.delete('one');

// データの削除(全部)
map.clear();

// keyを全部取得
var keys = map.keys(); // => MapIteratorが取得できる
// for of 構文はIteratorを回すことができる
for (var key of keys) {
    console.debug(key);
}

// 値の取得(values)
var values = map.values(); // => MapIteratorが取得できる
for (var value of values) {
    console.debug(value); // => "My key is a string." とか
}

// 値の取得(entries)
var entries = map.entries();
for (var entry of entries) {
    console.debug(entry); // => ["one", "My key is a string."] とか
}

// 値の取得(forEach)
map.forEach(function (value, key, map) {
    console.debug(value, key, map); // => My key is a string. one Map {}  とか
});
Key-Value構造のデータ構造で、それに合わせた様々なインターフェースがあるのは、とてもありがたいなぁと思う今日この頃です。 Objectでデータを格納するよりもmap.keys()map.has()など使い勝手が良いと感じます。

またMapの各ブラウザの実装状況は、kangax.github.ioをご覧頂くと把握することができます。



Set

Setでは、重複しない一意なデータのコレクションを扱うことができます。 ここで言う「一意な」という定義は後ほど扱います。 似たようなデータ構造に配列がありますが、配列では重複したデータ(同じデータ)を複数格納できる点が異なります。
Setについても例を見てみたいと思います。

// 初期化
var set = new Set();

// 値付きの初期化
// 数値、文字列、関数、など色々と入る.
var set = new Set([1, 'one', function (){}, document.body]);

// 値の追加
set.add(2);

// 値の存在確認
set.has('one'); // => true

// 値の削除
set.delete(1);

// 格納してあるデータ数
set.size; // => 4

// 値の取得(values)
for (var value of set.values()) {
    console.debug(value); // => 'one'、など
}

// 値の取得(entities)
for (var entry of set.entries()) {
    console.debug(entry); // => ['one', 'one']、など
}

// 値の取得(forEach)
set.forEach(function (value1, value2, set) {
    console.debug(value1, value2, set); // => one one Set
});
Setの最も便利なところは「値が重複しない」という特徴だと思います。 例えば以下のように、APIレスポンスをサーバーから受け取った場合に、ユニークユーザー数は何人かを知る時に便利に使えそうです。
getDataFromAPI(function (results) {
    var set = new Set();
    results.forEach(function (result) {
        set.add(result.userId);
    });

    var numOfUser = set.size;
    alert('ユニークユーザー数は' + numOfUser + 'です');
});
上記の場合にset.add(result.userId)で、UserIdが重複している場合にも気にせずaddできる点が素敵です。 Setも使い勝手の良いコレクションAPIなので、ぜひぜひ使えるようになりたいところです。



同一性の定義

MapのキーやSetの値は、重複を許さないという話が上記でありましたが、重複とは具体的にどういう定義なのでしょうか。 ECMAScript6の仕様書によると、SameValueZeroのアルゴリズムが使われるようです。ここでは簡単に引用して、ご紹介させて頂きます。
1. ReturnIfAbrupt(x).
2. ReturnIfAbrupt(y).
3. If Type(x) is different from Type(y), return false.
4. If Type(x) is Undefined, return true.
5. If Type(x) is Null, return true.
6. If Type(x) is Number, then
  6.1. If x is NaN and y is NaN, return true.
  6.2. If x is +0 and y is -0, return true.
  6.3. If x is -0 and y is +0, return true.
  6.4. If x is the same Number value as y, return true.
  6.5. Return false.
7. If Type(x) is String, then
  7.1. If x and y are exactly the same sequence of code units (same length and same code units in corresponding positions) return true; otherwise, return false.
8. If Type(x) is Boolean, then
  8.1. If x and y are both true or both false, then return true; otherwise, return false.
9. If Type(x) is Symbol, then
  9.1. If x and y are both the same Symbol value, then return true; otherwise, return false.
10. Return true if x and y are the same Object value. Otherwise, return false.
引用:http://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero

ECMAScriptの仕様書は初めて中身を見ましたが、こんな感じで定義されているんですね。 意外と読みやすいなぁと思いました。



参考資料

MapとSetについては、以下の記事を参考にしました。

Collecting and Iterating, the ES6 Way | HTML5Rocks

Map | MDN

Set | MDN

最後に

Chrome38からMapSetが使えるようになったので、それぞれのAPIを調べてみました。 APIの紹介だったので、ちょっと地味でしたねw。

今後も本ブログでは、フロントエンドに関する情報を書きたいと思います。気になった方はぜひ、本ブログのRSSTwitterをフォローして頂けると幸いです ^ ^。
最後までご覧頂きましてありがとうございました!





こんな記事もいかがですか?

RSS画像

もしご興味をお持ち頂けましたら、ぜひRSSへの登録をお願い致します。