前言
映射 (map) 和集合 (set) 是 ES6 後新增的容器物件。映射是用來儲存以鍵/值對 (key-value pair) 為單位的非線性容器。集合的概念源自於數學上的集合論,用來表示獨特的 (unique) 資料存在的關係。
為什麼會把映射和集合放在一起講呢?因為映射和集合在概念上相當接近。我們可以把集合想成不限定鍵的型別,但值固定為布林的映射。甚至,我們可以用映射當基底資料結構,自行實作集合容器。
在 ES5 (含) 之前的年代,會用物件實字 (object literal) 來模擬映射和集合的功能;雖然現在仍然可以繼續使用物件實字來模擬映射和集合,能夠使用映射和集合物件時,應優先使用新的容器。
使用映射 (Map)
建立映射物件
用 Map 建構函式可建立新的映射物件:
let map = new Map([
["one", "eins"],
["two", "zwei"],
["three", "drei"]
]);
這時候,我們會以二維陣列做為 Map
建構函式的參數,可以一次建立所需的鍵/值對。
也可以先建立空映射物件後再逐一增添鍵/值對:
let map = new Map();
map.set("one", "eins");
map.set("two", "zwei");
map.set("three", "drei");
存取映射中的元素
我先在上一節看過了,使用 Map 物件的 set 函式可以儲存新的鍵值對。之後再以 get 函式藉由鍵取得值。參考下例:
let map = new Map();
map.set("one", "eins");
map.set("two", "zwei");
map.set("three", "drei");
assert(map.get("two") === "zwei", "It should be zwei");
// Map returns `undefined` when the key-value pair doesn't exist.
assert(typeof map.get("four") === "undefined", "It should be undefined");
// Home-made assertion.
function assert(cond, msg) {
if (!(cond)) {
throw msg;
}
}
映射的演算方式是以鍵取值,但不能以值取鍵。在儲存鍵值對時,鍵當成運算內部索引的資料,實際儲存起來的是內部索引和值。因此,只能進行單向取值。
走訪映射
走訪映射的方式是以 for
迴圈搭配 of
修飾字。我們可以根據自身的需求,以鍵、值、鍵值對等方式來走訪。
藉由 keys() 函式可提取出映射的鍵。搭配 for
迴圈即可走訪所有的元素。參考下例:
let map = new Map();
map.set("one", "eins");
map.set("two", "zwei");
map.set("three", "drei");
for (let k of map.keys()) {
console.log(`${k} -> ${map.get(k)}`);
}
如果我們只需要值的部分,可以改用 values() 函式來走訪映射。參考下例:
let map = new Map();
map.set("one", "eins");
map.set("two", "zwei");
map.set("three", "drei");
for (let v of map.values()) {
console.log(v);
}
如果我們鍵、值都要,除了先前的方式,也可以用 entries() 函式將整個鍵/值對同時取出。參考下例:
let map = new Map();
map.set("one", "eins");
map.set("two", "zwei");
map.set("three", "drei");
for (let e of map.entries()) {
console.log(`${e[0]} -> ${e[1]}`);
}
取出的 entry 是一個包含兩個元素的陣列,分別用索引值即可取出鍵、值。由於陣列取索引的運算會比映射取索引的開銷小,適度使用 entries()
會比只用 keys()
來得好。
移除映射中的元素
使用 delete() 函式可移除映射中已存在的鍵值對。參考下例:
let map = new Map();
map.set("one", "eins");
map.set("two", "zwei");
map.set("three", "drei");
assert(map.get("two") === "zwei", "It should be zwei");
// Delete a key-value pair.
map.delete("two");
// Map returns `undefined` when the key-value pair doesn't exist.
assert(typeof map.get("two") === "undefined", "It should be undefined");
// Home-made assertion.
function assert(cond, msg) {
if (!(cond)) {
throw msg;
}
}
移除鍵值對後,若再存取鍵值對,會回傳 undefined
。
使用集合 (Set)
建立集合物件
使用 Set() 建構函式即可建立集合物件:
let set = new Set([1, 1, 2, 3, 3, 4, 4, 4, 4, 5, 5]);
assert(set.size === 5, "The size should be 5");
// Home-made assertion.
function assert(cond, msg) {
if (!(cond)) {
throw msg;
}
}
在建立集合物件時,會自動去除重覆的元素。以本例來說,其物件長度為 5
。
也可以先建立空的集合物件後再逐一增加元素:
let set = new Set();
set.add(1);
set.add(2);
set.add(2);
set.add(3);
set.add(3);
set.add(3);
set.add(1);
assert(set.size === 3, "The size should be 3");
// Home-made assertion.
function assert(cond, msg) {
if (!(cond)) {
throw msg;
}
}
確認集合的元素存在
使用 has() 函式可確認集合中的元素是否存在。參考下例:
let set = new Set([1, 2, 3, 4, 5]);
assert(set.has(1), "1 should exist");
assert(!set.has(6), "6 should not exist");
// Home-made assertion.
function assert(cond, msg) {
if (!(cond)) {
throw msg;
}
}
走訪集合
由於集合只有值,沒有鍵,故使用 values() 函式搭配 for
迴圈來走訪集合。參考下例:
let set = new Set([1, 2, 3, 4, 5]);
for (let v of set.values()) {
console.log(v);
}
移除集合中的元素
使用 delete() 函式可移除集合中的元素。參考下例:
let set = new Set([1, 2, 3, 4, 5]);
assert(set.has(2), "2 should exist");
// Delete one element from the set.
set.delete(2);
assert(!set.has(2), "2 should not exist");
// Home-made assertion.
function assert(cond, msg) {
if (!(cond)) {
throw msg;
}
}
結語
透過本文,相信讀者可以學會映射和集合的用法。這兩種容器不僅在概念上相近,在 API 也有相似之處,故我們放在同一篇文章中。讀者可相互比較一下。