iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 22
0
Modern Web

JavaScript 忍者的修練--從下忍進階到中忍系列 第 22

Day 22: Map

ES6 新增了 Map 物件,它在結構上和物件一樣是 key-value 的組合,不同的地方在於:

  • 物件的 key 值一定要是基礎的資料型別而且限定 String, Number 或 Symbol,在 Map 裡則是任何資料型別(甚至是物件或者 HTML 元素)都可以當做 key 或 value。
  • 另一個相異的地方是項目儲存的順序,Map 會依照加入的順序存放,但是物件不會。
  • Map 有size屬性能得到裡面的數量,物件沒有。
  • Map 可迭代,物件不行。

建立 Map

// 建立空的 Map 物件
var map = new Map();

// 從既有的 iterable object (通常是陣列)建立 Map 物件
var map = new Map([iterable]);

Map 物件只能透過 Map constructor function 來建立,可以先建立空 Map 物件,再用set方法加入,或從現有的 ”iterable object” 來建立。

JavaScript iterable object 是指可以被迭代的物件,簡單的判斷法是能夠被for..of迴圈使用的物件,陣列是內建的 iterable object,通常會使用陣列來建立 Map。

建立 Map 的陣列需要一定格式,就是陣列項目必須是成對的,例如[[1, "one"], [2, "two"], [3, "three"]]。Map 建構器會將第一個值當做 key,另一個當做 value。

大木博士的實驗室接受全世界訓練師寄放寶可夢,讓他有樣本可以做研究。同一個物種會有不同訓練師送過來,為了區別牠們,大木博士使用 Map 來建立資料庫,同時為每一隻寶可夢做追踪記錄。

const oaksLab = new Map();

// 訓練師們寄放寶可夢在研究室
const pokemon1 = {
  name: "Pikachu",
  trainer: "Ash",
};

const pokemon2 = {
  name: "Pikachu",
  trainer: "Gary",
};

const pokemon3 = {
  name: "Psydock",
  trainer: "Misty",
};

// 接收寶可夢時,博士會為每一隻的狀況做記錄
oaksLab.set(pokemon1, {
	gender: "male",
	age: 2
});

oaksLab.set(pokemon2, {
	gender: "male",
	age: 3
});

oaksLab.set(pokemon3, {
	gender: "male",
	age: 1
});

/*
oaksLab: Map {
	{ name: 'Pikachu', trainer: 'Ash' } => { gender: 'male', age: 2 }, 
  { name: 'Pikachu', trainer: 'Gary' } => { gender: 'male', age: 3 }, 
  { name: 'Psydock', trainer: 'Misty' } => { gender: 'male', age: 1 }
}
*/

檢查 Map 物件能看到以上的對應關系,而第一組物件被當成 key 值,這在純物件是沒辦法做到的。

Map 的方法

get

找尋特定的項目用get,代入 key 值或者設立的變數名稱,會得到 value 的值。如果沒有這個項目會得到undefined

oaksLab.get(pokemon2);
// { gender: 'male', age: 3 }
oaksLab.get(pokemon4);
// undefined

size

檢查 Map 裡有多少組項目。

oaksLab.size;
// 3

has

使用has檢查某個 key 是否存在。

oaksLab.has(pokemon1); // true
oaksLab.has(pokemon3); // true
oaksLab.has(pokemon4); // false

delete, clear

當寶可夢被領回去了,使用delete刪除該項目。

oaksLab.delete(pokemon1);
oaksLab.size; // 2
oaksLab.has(pokemon1); // false

如果實驗室關閉了,博士把所有保管的寶可夢送回去,就用clear把 Map 給清空。

oaksLab.clear();
oaksLab.size; // 0

Map 的迭代

Map 是迭代物件,可以用for..of迴圈。

/*
oaksLab: Map {
  { name: 'Pikachu', trainer: 'Ash' } => { gender: 'male', age: 2 }, 
  { name: 'Pikachu', trainer: 'Gary' } => { gender: 'male', age: 3 }, 
  { name: 'Psydock', trainer: 'Misty' } => { gender: 'male', age: 1 }
}
*/

for(pokemon of oaksLab) {
	console.log(pokemon);
}

// [ { name: 'Pikachu', trainer: 'Ash' }, { gender: 'male', age: 2 } ] 
// [ { name: 'Pikachu', trainer: 'Gary' }, { gender: 'male', age: 3 } ] 
// [ { name: 'Psydock', trainer: 'Misty' }, { gender: 'male', age: 1 } ] 

每次迭代裡,會得到擁有二個項目的陣列,第一個項目是 key 值,第二個項目是 value 值。我們也可以用keysvalues這二個方法來迭代 Map 裡的 key 和 value。

for(key of oaksLab.keys()) {
	console.log(key);
}
// { name: 'Pikachu', trainer: 'Ash' }
// { name: 'Pikachu', trainer: 'Gary' }
// { name: 'Psydock', trainer: 'Misty' }

for(value of oaksLab.values()) {
	console.log(value);
}
// { gender: 'male', age: 2 }
// { gender: 'male', age: 3 }
// { gender: 'male', age: 1 }

除了keysvalue之外,還有一個 entries方法,這三個方法回傳的值都是 iterator object,表示除了可以使用 for..of迴圈之外,還可以用.next()來分段執行,像 generator 一樣。

const entryIterator = oaksLab.entries();
entryIterator.next();
// { value: [ { name: 'Pikachu', trainer: 'Ash' }, { gender: 'male', age: 2 } ], done: false } 
entryIterator.next();
// { value: [ { name: 'Pikachu', trainer: 'Gary' }, { gender: 'male', age: 3 } ], done: false } 
entryIterator.next();
// { value: [ { name: 'Psydock', trainer: 'Misty' }, { gender: 'male', age: 1 } ], done: false } 
entryIterator.next();
// { value: undefined, done: true } 

const keyIterator = oaksLab.keys();
keyIterator.next();
// { value: { name: 'Pikachu', trainer: 'Ash' }, done: false } 
keyIterator.next();
// { value: { name: 'Pikachu', trainer: 'Gary' }, done: false }
keyIterator.next();
// { value: { name: 'Psydock', trainer: 'Misty' }, done: false } 
keyIterator.next();
// { value: undefined, done: true } 

const valueIterator = oaksLab.values();
valueIterator.next();
// { value: { gender: 'male', age: 2 }, done: false }
valueIterator.next();
// { value: { gender: 'male', age: 3 }, done: false }
valueIterator.next();
// { value: { gender: 'male', age: 1 }, done: false }
valueIterator.next();
// { value: undefined, done: true } 

上一篇
Day 21: 陣列
下一篇
Day 23: Set
系列文
JavaScript 忍者的修練--從下忍進階到中忍30

尚未有邦友留言

立即登入留言