為什要使用新的Map Set
在沒有 Map
, Set
這兩個(gè)數(shù)據(jù)類型之前盾碗, javascript 本身就可以簡單實(shí)現(xiàn)類似哈希表的東西: 基礎(chǔ)的類型-對象(Object)
一個(gè)普通的對象本身就是一個(gè) 開放的鍵值對集合乐疆,可以進(jìn)行獲取牺丙、設(shè)置、刪除蕾额、遍歷--任何一個(gè)哈希表支持的操作糊闽,那么為什么要es6 要出新的Map Set數(shù)據(jù)結(jié)構(gòu)類型呢?
- 作為查詢表使用的對象虏冻,不能既支持方法又保證避免沖突。
- 因?yàn)橐吹糜?code>Object.create(null)而非直接寫{}弹囚,要么得小心地避免把
Object.prototype.toString
之類的內(nèi)置方法名作為鍵名來存儲(chǔ)數(shù)據(jù)。 - 對象的鍵總是字符串(es6中也可以是
Symbol
)而不能是另一個(gè)對象领曼。 - 沒有郵箱的獲取屬性個(gè)數(shù)的方法鸥鹉。
- ES6中又出現(xiàn)了新問題:純粹的對象不可遍歷,也就是庶骄,它們不能配合
for-of
循環(huán)或...
操作符等語法毁渗。
雖然在一般的情況下,直接使用對象是很方便单刁,直接的并且正確的選擇灸异,但是ES6中的集合本來就是為避免用戶數(shù)據(jù)與內(nèi)置方法沖突而設(shè)計(jì)的,不會(huì)將數(shù)據(jù)作為屬性暴露出來。也就是說肺樟,obj.key
和obj[key]
不能在用來訪問數(shù)據(jù)了檐春,取而代之的是 map.get(key)
,并且不能通過原型鏈來繼承其他屬性么伯。
Map
和Set
的鍵都可以是對象疟暖,這一點(diǎn)和傳統(tǒng)的 Object 很不一樣
set: 無序不重復(fù)值的列表
一個(gè)Set不會(huì)包含相同元素。試圖再次加入一個(gè)已有元素不會(huì)產(chǎn)生任何效果
包含的操作
-
new Set
:創(chuàng)建一個(gè)新的田柔、空的Set俐巴。 -
new Set(iterable)
:從任何可遍歷數(shù)據(jù)中提取元素,構(gòu)造出一個(gè)新的集合硬爆。 -
set.size
:獲取集合的大小欣舵,即其中元素的個(gè)數(shù)。 -
set.has(value)
:判定集合中是否含有指定元素缀磕,返回一個(gè)布爾值缘圈。 -
set.add(value)
:添加元素。如果與已有重復(fù)虐骑,則不產(chǎn)生效果准验。 -
set.delete(value)
:刪除元素。如果并不存在廷没,則不產(chǎn)生效果糊饱。.add()
和.delete()
都會(huì)返回集合自身,所以我們可以用鏈?zhǔn)秸Z法颠黎。 -
set[Symbol.iterator]()
:返回一個(gè)新的遍歷整個(gè)集合的迭代器另锋。一般這個(gè)方法不會(huì)被直接調(diào)用,因?yàn)閷?shí)際上就是它使集合能夠被遍歷狭归,也就是說夭坪,我們可以直接寫for (v of set) {...}
等等。 -
set.forEach(f)
:直接用代碼來解釋好了过椎,它就像是for (let value of set) { f(value, value, set); }
的簡寫室梅,類似于數(shù)組的.forEach()
方法。 -
set.clear()
:清空集合疚宇。 -
set.keys()
亡鼠、set.values()
和set.entries()
返回各種迭代器,它們是為了兼容Map而提供的敷待,所以我們待會(huì)兒再來看间涵。
注意
在 Set 內(nèi)部 NaN
類型的值是相等的(實(shí)際上 NaN
不等于任何值),不能傳兩個(gè) NaN 的值
let set = new Set();
let a = NaN;
let b = NaN;
set.add(a);
set.add(b);
set // Set {NaN}
上面代碼向 Set 實(shí)例添加了兩個(gè)NaN榜揖,但是只能加入一個(gè)勾哩。這表明抗蠢,在 Set 內(nèi)部,兩個(gè)NaN是相等思劳。
map:無序鍵不重復(fù)鍵值對
一個(gè) Map 不會(huì)包含相同的 鍵所構(gòu)成的鍵值對迅矛,試圖再次加入一個(gè)已存在的鍵的元素會(huì)覆蓋前者。
如果讀取一個(gè)未知的鍵敢艰,則返回undefined诬乞。
包含的操作
-
new Map
:返回一個(gè)新的、空的Map
钠导。 -
new Map(pairs)
:根據(jù)所含元素形如[key, value]
的數(shù)組pairs
來創(chuàng)建一個(gè)新的Map
震嫉。這里提供的pairs
可以是一個(gè)已有的Map
對象,可以是一個(gè)由二元數(shù)組組成的數(shù)組牡属,也可以是逐個(gè)生成二元數(shù)組的一個(gè)生成器票堵,等等。 -
map.size
:返回Map
中項(xiàng)目的個(gè)數(shù)逮栅。 -
map.has(key)
:測試一個(gè)鍵名是否存在悴势,類似key in obj
。 -
map.get(key)
:返回一個(gè)鍵名對應(yīng)的值措伐,若鍵名不存在則返回undefined
特纤,類似obj[key]
。 -
map.set(key, value)
:添加一對新的鍵值對侥加,如果鍵名已存在就覆蓋捧存。 -
map.delete(key)
:按鍵名刪除一項(xiàng),類似delete obj[key]
担败。 -
map.clear()
:清空Map
昔穴。 -
map[Symbol.iterator]()
:返回遍歷所有項(xiàng)的迭代器,每項(xiàng)用一個(gè)鍵和值組成的二元數(shù)組表示提前。 -
map.forEach(f)
類似for (let [key, value] of map) { f(value, key, map); }
吗货。這里詭異的參數(shù)順序,和Set
中一樣狈网,是對應(yīng)著Array.prototype.forEach()
宙搬。 -
map.keys()
:返回遍歷所有鍵的迭代器。 -
map.values()
:返回遍歷所有值的迭代器拓哺。 -
map.entries()
:返回遍歷所有項(xiàng)的迭代器害淤,就像map[Symbol.iterator]()
。實(shí)際上拓售,它們就是同一個(gè)方法,不同名字镶奉。
轉(zhuǎn)換方法
Set => Array
- 擴(kuò)展運(yùn)算符(
...
)
var a = [...new Set([1,2,3,4])]
a // [1,2,3,4]
Map => Array
var map = new Map();
map.set(true, 7);
map.set({a: '1'}, ['abc']);
var arr = [...map];
arr // [[true, 7], [{ a: '1' }, ['abc']]]
Array => Map
new Map([
[true, 7],
[{ a: '1' }, ['abc']]
])// Map {true=>7, {a: '1'}=>['abc']}
Map 轉(zhuǎn)換為對象
如果所有 Map 的鍵都是字符串础淤,它可以轉(zhuǎn)為對象崭放。
function strMapToObj(strMap) {
let obj = Object.create(null); // 創(chuàng)建新的空對象
for (let [k,v] of strMap) { // 遍歷 Map 對象
obj[k] = v; // 賦值空對象
}
return obj;
}
const myMap = new Map()
.set('yes', true)
.set('no', false);
strMapToObj(myMap)
// { yes: true, no: false }
例子來自 ECMAScript 6 入門 阮一峰
對象轉(zhuǎn)為Map
function objToStrMap(obj) {
let strMap = new Map();
for (let key of Object.keys(obj)) {
strMap.set(key, obj[key]);
}
return strMap;
}
objToStrMap({yes: true, no: false})
// Map {"yes" => true, "no" => false}
例子來自 ECMAScript 6 入門 阮一峰
Map 轉(zhuǎn)為 Json
Map 轉(zhuǎn)為 Json 分為兩種情況
- 對象Json, Map 的鍵為字符串
function strMapToJson(strMap) {
return JSON.stringify(strMapToObj(strMap))
}
let myMap = new Map().set('yes', true).set('no', false);
strMapToJson(myMap)
// '{"yes":true,"no":false}'
- 數(shù)組Json,Map 的鍵有非字符串
function mapToArrayJson(map) {
return JSON.stringify([...map]);
}
let myMap = new Map().set(true, 7).set({foo: 3}, ['abc']);
mapToArrayJson(myMap)
// '[[true,7],[{"foo":3},["abc"]]]'
例子來自 ECMAScript 6 入門 阮一峰
Json 轉(zhuǎn)為 Map
- 鍵名都是字符串
function jsonToStrMap(jsonStr) {
return objToStrMap(JSON.parse(jsonStr));
}
jsonToStrMap('{"yes": true, "no": false}')
// Map {'yes' => true, 'no' => false}
- 整個(gè) JSON 就是一個(gè)數(shù)組
function jsonToMap(jsonStr) {
return new Map(JSON.parse(jsonStr));
}
jsonToMap('[[true,7],[{"foo":3},["abc"]]]')
// Map {true => 7, Object {foo: 3} => ['abc']}
例子來自 ECMAScript 6 入門 阮一峰