JavaScript

JavaScriptのMapの使い方と具体例

JavaScriptのMapはとても便利なので詳しくみていきましょう。

この記事の目次
  1. Mapの使い方
  2. Mapとset
  3. setとチェーンして使用
  4. Mapとget
  5. Mapとtrue/falseを上手に使う
  6. Mapとhas
  7. Mapとdelete
  8. Mapとsize
  9. Mapとclear
  10. 配列をキーとして使う
  11. DOMを操作する
  12. たくさん値があるときに便利にセットする方法
  13. オブジェクトをMapに変換する
  14. Mapでforループを使う
  15. Mapを配列に変換する
  16. map()で返された関数の値を別の関数を作って返す
  17. mapの挙動まとめ
  18. mapから、重複のない値のみの配列をつくりたい

JavaScriptのMapはとても便利なので詳しくみていきましょう。

Mapの使い方

Mapオブジェクトはキーと値のペアを保持します。

そして、キーが最初に挿入された順序を覚えてくれているので、それを利用することができます。

キーや値には任意の値 (オブジェクトとプリミティブ値)を使用することができるため、Mapはどんなデータ型でも使うことができます。
まずはmapに情報をセットする方法をみていきましょう。

Mapとset

{
const rest = new Map();
rest.set('name', '居酒屋エンジニア');
rest.set('1', '東京、日本');
console.log(rest); //Map(2) {"name" => "居酒屋エンジニア", "1" => "東京、日本"}
}

このようにMapは次々とsetで設定された値を格納していくことができます。

setとチェーンして使用

setはチェーンして設定していくことができます。

{
  const rest = new Map();
rest.set('categories', ['中華', '和食','イタリアン', 'フレンチ', 'アフリカン']).set('open', 10).set('close', 22).set(true, '営業中です:)').set(false, '閉店中ですm(_ _)m');
}

Mapとget

{
//getで取得
const rest = new Map();
rest.set('categories', ['中華', '和食','イタリアン', 'フレンチ', 'アフリカン']).set('open', 10).set('close', 22).set(true, '営業中です:)').set(false, '閉店中ですm(_ _)m');
console.log(rest.get('name')); //居酒屋エンジニア
console.log(rest.get(true)); //営業中です:)
console.log(rest.get('categories')); //(5) ["中華", "和食", "イタリアン", "フレンチ", "アフリカン"]
}

Mapとtrue/falseを上手に使う

{
//true/falseを上手に使う
const rest = new Map();
rest.set('categories', ['中華', '和食','イタリアン', 'フレンチ', 'アフリカン']).set('open', 10).set('close', 22).set(true, '営業中です:)').set(false, '閉店中ですm(_ _)m');
const time = 20;
const openMsg = rest.get(time > rest.get('open') && time < rest.get('close'));
console.log(openMsg); //trueが返されて「営業中です:)」が表示される
}

Mapとhas

{
//has
const rest = new Map();
rest.set('categories', ['中華', '和食','イタリアン', 'フレンチ', 'アフリカン']).set('open', 10).set('close', 22).set(true, '営業中です:)').set(false, '閉店中ですm(_ _)m');
console.log(rest.has('categories')); //true
}

Mapとdelete

{
//delete
rest.delete(1);
}

Mapとsize

{
//size
const rest = new Map();
rest.set('categories', ['中華', '和食','イタリアン', 'フレンチ', 'アフリカン']).set('open', 10).set('close', 22).set(true, '営業中です:)').set(false, '閉店中ですm(_ _)m');
console.log(rest.size);//5
}

sizeはlengthの代わりに使うと便利です。

Mapとclear

{
//clear
rest.clear();
}

配列をキーとして使う

 

//配列をキーとして使うとき
const arr = [2,2];
rest.set(arr, 'テスト');
console.log(rest);
console.log(rest.size);

console.log(rest.get(arr));

配列をキーとして呼び出すときは、console.log(rest.get([2,2]))として呼び出すこととはできません。
それはメモリーと参照のところで説明しています。
そのため、配列をキーとするのであれば、一度変数に入れてから使う必要があります。
整理すると、Mapへはsetを使うことで、[2,2]といった配列でもキーとして設定することができますが、呼び出すときには、[2,2]では完全に新しい配列になってしまっているため呼び出せません。
そのため、キーとなる部分を変数で置き換えます。

DOMを操作する

//DOMを操作する
const h1 = new Map();
h1.set(document.querySelector('h1'), 'Heading');
console.log(h1);

実際にコンソールで確認すると、h1にカーソルをあわせることでh1を要素選択できることがわかります。

スポンサーリンク

たくさん値があるときに便利にセットする方法

{
//たくさん値があるときに便利にセットする方法
const question = new Map([
  ['質問', '世界で最も使われているプログラミング言語はなんでしょうか。'],
  [1, 'C'],
  [2, 'Java'],
  [3, 'JavaScript'],
  ['正解', 3],
  [true, '正解'],
  [false, '残念、もう一度'],
]);
console.log(question);
}

setを使ってもいいのですが、このようにすると、見やすくいっきに設定することができます。

オブジェクトをMapに変換する

次のオブジェクトをMapに変換したいとします。
上のMapをコンソールでみると「entries」ということばが見つかります。とてもオブジェクトに似た形をしているのがわかると思います。
オブジェクトにObject.entries()を使うことで簡単にMapに変換することができます。

{
//オブジェクトをMapに変換する

const openingHours = {
  wed: {
    open: 12,
    close: 22,
  },
  thu: {
    open: 11,
    close: 23,
  },
  fri: {
    open: 0, // Open 24 hours
    close: 24,
  },
};
console.log(openingHours);
//const hoursMap = new Map(openingHours); これはできない。objectはiterableじゃないため。
const hoursMap = new Map(Object.entries(openingHours));
console.log(hoursMap);
}

オブジェクトはiterableではないため、forループがつかえません。
しかし、mapはiterableのため、forループが使えます。
そして、オブジェクトからmapへの変換はとても簡単です。

Mapでforループを使う

{
const question = new Map([
  ['質問', '世界で最も使われているプログラミング言語はなんでしょうか。'],
  [1, 'C'],
  [2, 'Java'],
  [3, 'JavaScript'],
  ['正解', 3],
  [true, '正解'],
  [false, '残念、もう一度'],
]);

console.log(question.get('質問'));
世界で最も使われているプログラミング言語はなんでしょうか。
for (const [key, value] of question) {
  if(typeof key === 'number') console.log(`答えは ${key}: ${value}`);
  答えは 1: C
  答えは 2: Java
  答えは 3: JavaScript
}

const answer = Number(prompt('あなたの答えは?'));
console.log(answer);
console.log(question.get(question.get('正解') === answer));
}

question.get(‘正解’) === answerという条件がtrueの場合、すでにMapに [true, ‘正解’]と返す配列が入っていますので、
3という正解が返ってくれば、question.get(true)という形に変換されます。
それ以外がanswerとして回答されると、question.get(false)となり、falseの文が返されます。

Mapを配列に変換する

[]をつけるだけなのでとても簡単です。

{
const question = new Map([
  ['質問', '世界で最も使われているプログラミング言語はなんでしょうか。'],
  [1, 'C'],
  [2, 'Java'],
  [3, 'JavaScript'],
  ['正解', 3],
  [true, '正解'],
  [false, '残念、もう一度'],
]);

console.log([...question]);
// entries()を使うとキーとバリューを取り出せる
console.log([...question.keys()]);
console.log([...question.values()]);
}

map()で返された関数の値を別の関数を作って返す

配列に何らかの処理をして、その結果を別の配列にしたい場合があります。
そんなときにmap()を使います。
map()は返された関数の値を別の関数を作って返すことができます。

たとえば10円ずつ値下げしたいとします。
すでに200円,300円,400円という値段にそれぞれ10円引いた結果がほしい場合、次のようになります。

 'use strict';
  {
    const prices = [200, 300, 400];

    const discountedPrices = prices.map((price) => {
      return price - 10;
    });
    console.log(discountedPrices);

    //より短く書く場合、次のようにもかけます。
    //const prices = [200, 300, 400];
    // const discountedPrices = price.map(price => price - 10);
    //console.log(discountedPrices);
  }

まずmap()で返される値を格納するため、定数を作ってあげます。
今回は割引するのでdiscountedPricesという定数名にします。
そして、引数としてpriceを用意しておきます。
返す処理を書いてreturnすることで、pricesのそれぞれの値が引数priceに渡されます。
そしてそれぞれ10円値引きした値を返し、discountedPricesに格納すことができます。

mapの挙動まとめ

const gameEvents = new Map([
  [15, '⚽️ ゴール'],
  [33, '🔁 選手交代'],
  [48, '⚽️ ゴール'],
  [61, '🔁 選手交代'],
  [67, '🔶 イエローカード'],
  [69, '🔴 レッドカード'],
  [70, '🔁 選手交代'],
  [76, '🔁 選手交代'],
  [78, '⚽️ ゴール'],
  [85, '⚽️ ゴール'],
  [90, '🔶 イエローカード'],
]);

/* ========================= */
/*   lengthを取得したい  */
/* ========================= */
console.log(gameEvents.size);//11


/* ========================= */
/*   mapの状態で値とキーを取得したい  */
/* ========================= */

//mapの状態でvaluesを取得する
console.log(gameEvents.values());
/*
MapIterator {"⚽️ ゴール", "🔁 選手交代", "⚽️ ゴール", "🔁 選手交代", "🔶 イエローカード", …}
[[Entries]]
0: "⚽️ ゴール"
1: "🔁 選手交代"
2: "⚽️ ゴール"
3: "🔁 選手交代"
4: "🔶 イエローカード"
5: "🔴 レッドカード"
6: "🔁 選手交代"
7: "🔁 選手交代"
8: "⚽️ ゴール"
9: "⚽️ ゴール"
10: "🔶 イエローカード"
*/
//mapの状態でkeysを取得する
console.log(gameEvents.keys());
/*返される値
MapIterator {15, 33, 48, 61, 67, …}
[[Entries]]
0: 15
1: 33
2: 48
3: 61
4: 67
5: 69
6: 70
7: 76
8: 78
9: 85
10: 90
*/


/* ========================= */
/*   一文で取得したい  */
/*   スプレッド構文  */
/* ========================= */

//スプレッド構文でvaluesだけ取得する
console.log(...gameEvents.values());
//⚽️ ゴール 🔁 選手交代 ⚽️ ゴール 🔁 選手交代 🔶 イエローカード 🔴 レッドカード 🔁 選手交代 🔁 選手交代 ⚽️ ゴール ⚽️ ゴール 🔶 イエローカード

//スプレッド構文でkeysだけ取得する
console.log(...gameEvents.keys());
//15 33 48 61 67 69 70 76 78 85 90


/* ========================= */
/*   mapを配列で取得したい  */
/*   配列+スプレッド構文  */
/* ========================= */

//配列+スプレッド構文でvaluesだけの配列をつくる
console.log([...gameEvents.values()]);
//(11) ["⚽️ ゴール", "🔁 選手交代", "⚽️ ゴール", "🔁 選手交代", "🔶 イエローカード", "🔴 レッドカード", "🔁 選手交代", "🔁 選手交代", "⚽️ ゴール", "⚽️ ゴール", "🔶 イエローカード"]

//配列+スプレッド構文でkeysだけの配列をつくる
console.log([...gameEvents.keys()]);
//(11) [15, 33, 48, 61, 67, 69, 70, 76, 78, 85, 90]

/* ========================= */
/*   mapの重複を削除したい  *
/*   set+配列+スプレッド構文  */
/* ========================= */
//set+配列+スプレッド構文でvaluesだけのsetをつくる
console.log(new Set([...gameEvents.values()]));
/*
Set(4) {"⚽️ ゴール", "🔁 選手交代", "🔶 イエローカード", "🔴 レッドカード"}
[[Entries]]
0: "⚽️ ゴール"
1: "🔁 選手交代"
2: "🔶 イエローカード"
3: "🔴 レッドカード"
*/

//set+配列+スプレッド構文でkeysだけのsetをつくる
console.log(new Set([...gameEvents.keys()]));
/*
Set(11) {15, 33, 48, 61, 67, …}
[[Entries]]
0: 15
1: 33
2: 48
3: 61
4: 67
5: 69
6: 70
7: 76
8: 78
9: 85
10: 90
*/


/* ========================= */
/*   ループとの組み合わせ  */
/* ========================= */
for (const [key, value] of gameEvents) {
  const half = key <= 45 ? '1st': '2nd'; 
   console.log(`[${half} HALF] ${key}: ${value}`);
 }

 /*
 Set(11) {15, 33, 48, 61, 67, …}
[1st HALF] 15: ⚽️ ゴール
[1st HALF] 33: 🔁 選手交代
[2nd HALF] 48: ⚽️ ゴール
[2nd HALF] 61: 🔁 選手交代
[2nd HALF] 67: 🔶 イエローカード
[2nd HALF] 69: 🔴 レッドカード
[2nd HALF] 70: 🔁 選手交代
[2nd HALF] 76: 🔁 選手交代
[2nd HALF] 78: ⚽️ ゴール
[2nd HALF] 85: ⚽️ ゴール

  */

mapから、重複のない値のみの配列をつくりたい

  1. mapのvalues()をスプレッド構文を使って配列にする(重複のある値のみの配列がつくれる)
  2. それをsetにセットして新しい変数に格納する(重複した値が取り除かれる)
  3. setから配列に変換する

という順番です。


const gameEvents = new Map([
  [15, '⚽️ ゴール'],
  [33, '🔁 選手交代'],
  [48, '⚽️ ゴール'],
  [61, '🔁 選手交代'],
  [67, '🔶 イエローカード'],
  [69, '🔴 レッドカード'],
  [70, '🔁 選手交代'],
  [76, '🔁 選手交代'],
  [78, '⚽️ ゴール'],
  [85, '⚽️ ゴール'],
  [90, '🔶 イエローカード'],
]);
let eventsSet = new Set([...gameEvents.values()]);
console.log(eventsSet);
//Set(4) {"⚽️ ゴール", "🔁 選手交代", "🔶 イエローカード", "🔴 レッドカード"}

const events = [...new Set(eventsSet)];//setから配列に変換
console.log(events);
/*
["⚽️ ゴール", "🔁 選手交代", "🔶 イエローカード", "🔴 レッドカード"]
0: "⚽️ ゴール"
1: "🔁 選手交代"
2: "🔶 イエローカード"
3: "🔴 レッドカード"
*/

Setに関しては次の記事を参考にしてみてください。
JavaScriptの配列とSetとオブジェクトとMapはどう使い分けるべきか?
JavaScriptの重複を消すことができるSetの使い方と具体例

スポンサーリンク