Map
傳統上我們使用 Object 建立 key/value-pair 資料結構,來模擬 maps。
但缺點是無法使用非字串值的key。ES6的Map就解決這樣的問題了!1
2
3
4
5
6
7
8
9const m = {};
const x = {id:1},
y = {id:2};
m[x] = "foo"; // 這裡的key變成 [object Objec]
m[y] = "bar"; // 這裡的key變成 [object Objec]
m[x]; // bar
m[y]; // bar1
2
3
4
5
6
7
8
9const m = new Map();
const x = {id:1},
y = {id:2};
m.set(x,"foo");
m.set(y,"bar");
m.get(x); // foo
m.get(y); // barset(key,value)
- 替 Map 新增一個鍵/值並回傳該Map
- key 可以是任何型態
- 如果key已經存在,則會蓋掉原有的值
set方法會返回該Map,所以可以一直串接
1
2
3
4
5
6
7
8
9
10const m = new Map();
m.set('edition', 6)
m.set(262, 'standard')
m.set(undefined, 'nah')
let map = new Map()
.set(1, 'a')
.set(2, 'b')
.set(3, 'c');
get(key)
- 讀取對應key的鍵值,若找不到回傳
undefined
1
2
3
4
5const m = new Map();
const func = ()=>{console.log('Hello World!')};
m.set(func,'Hello Map');
m.get(func) //Hello Map
m.get('hi') // undefined- 讀取對應key的鍵值,若找不到回傳
size
- 返回Map成員的總數量
new Map().size ;
- 返回Map成員的總數量
delete(key)
刪除key的某個值,返回布林值,true代表刪除成功
1
2
3
4
5
6const m = new Map();
m.set(undefined, 'nah');
m.has(undefined) // true
m.delete(undefined)
m.has(undefined) // false
has(key)
返回布林值,判斷某個key是否存在Map中
1
2
3
4
5
6
7
8
9
10const m = new Map();
m.set('edition', 6);
m.set(262, 'standard');
m.set(undefined, 'nah');
m.has('edition') // true
m.has('years') // false
m.has(262) // true
m.has(undefined) // true
clear
- 刪除Map所有值,不會返回值
new Map().clear() ;
- 刪除Map所有值,不會返回值
Map 迭代
- keys()
- values()
- entries()
- forEach()
- Map迭代順序是依照加入的順序
Map 結構的默認遍歷器接口(Symbol.iterator屬性),就是entries方法
1
map[Symbol.iterator] === map.entries // true
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36const map = new Map([
['F', 'no'],
['T', 'yes'],
]);
for (let key of map.keys()) {
console.log(key);
}
// "F"
// "T"
for (let value of map.values()) {
console.log(value);
}
// "no"
// "yes"
for (let item of map.entries()) {
console.log(item[0], item[1]);
}
// "F" "no"
// "T" "yes"
// 或者
for (let [key, value] of map.entries()) {
console.log(key, value);
}
// "F" "no"
// "T" "yes"
// 等同於使用map.entries()
for (let [key, value] of map) {
console.log(key, value);
}
// "F" "no"
// "T" "yes"
Map 轉為陣列幾種方式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17const map = new Map([
[1, 'one'],
[2, 'two'],
[3, 'three'],
]);
[...map.keys()]
// [1, 2, 3]
[...map.values()]
// ['one', 'two', 'three']
[...map.entries()]
// [[1,'one'], [2, 'two'], [3, 'three']]
[...map]
// [[1,'one'], [2, 'two'], [3, 'three']]forEach
與陣列forEach相似
WeekSet
WeekSet
與map
外部行為大致相同- 只接受物件作為鍵值,若物件本身被GC了,
WeekSet
中的條目(entry)也會被移除 - 沒有size特性,也沒有clear()方法,也沒有提供任何迭代方法
承上
WeakMap
只有四個方法可用:get()、set()、has()、delete()1
2
3
4
5
6
7
8
9const m = new WeekMap();
let x = {id:1},
y = {id:2};
m.set(x,"foo");
m.has(x); // true
m.has(y); // false如果作為map鍵值的物件會被刪除或可能被GC,那麼
WeekMap
會是更好的選擇WeakMap 的用途例子
DOM 作為鍵名
1
2
3
4
5
6
7
8
9
10let myElement = document.getElementById('logo');
let myWeakmap = new WeakMap();
myWeakmap.set(myElement, {timesClicked: 0});
myElement.addEventListener('click', function() {
let logoData = myWeakmap.get(myElement);
logoData.timesClicked++;
}, false);
/*一旦這個 DOM 節點刪除,該狀態就會自動消失,不存在內存洩漏風險*/私有屬性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24const _counter = new WeakMap();
const _action = new WeakMap();
class Countdown {
constructor(counter, action) {
_counter.set(this, counter);
_action.set(this, action);
}
dec() {
let counter = _counter.get(this);
if (counter < 1) return;
counter--;
_counter.set(this, counter);
if (counter === 0) {
_action.get(this)();
}
}
}
const c = new Countdown(2, () => console.log('DONE'));
c.dec()
c.dec() // DONE
/* 一旦c被刪除,Countdown 內部的 _counter和_action也就隨之消失,不會造成內存洩漏 */