Map和Set對象
前置知識:
Map和Set對象是在ES6中被引入的适室,作為一種由key
值標記的數(shù)據(jù)容器嫡意。
Map和Set對象承載的數(shù)據(jù)元素可以按照插入時的順序,被迭代遍歷捣辆。
1.Set對象
介紹:
Set
數(shù)據(jù)結(jié)構(gòu)類似數(shù)組蔬螟,但所有成員的值唯一。
Set
本身為一個構(gòu)造函數(shù)罪帖,用來生成Set
數(shù)據(jù)結(jié)構(gòu)促煮,使用add
方法來添加新成員邮屁。
let a = new Set();
[1,2,2,1,3,4,5,4,5].forEach(x=>a.add(x));
for(let k of a){
console.log(k)
};
// 1 2 3 4 5
基礎(chǔ)使用:
let a = new Set([1,2,3,3,4]);
[...a]; // [1,2,3,4]
a.size; // 4
// 數(shù)組去重
[...new Set([1,2,3,4,4,4])];// [1,2,3,4]
注意:
- 向
Set
中添加值的時候,不會類型轉(zhuǎn)換菠齿,即5
和'5'
是不同的佑吝。
[...new Set([5,'5'])]; // [5, "5"]
屬性和方法:
-
屬性:
-
Set.prototype.constructor
:構(gòu)造函數(shù),默認就是Set
函數(shù)绳匀。 -
Set.prototype.size
:返回Set
實例的成員總數(shù)芋忿。
-
-
操作方法:
-
add(value)
:添加某個值,返回 Set 結(jié)構(gòu)本身疾棵。 -
delete(value)
:刪除某個值戈钢,返回一個布爾值,表示刪除是否成功是尔。 -
has(value)
:返回一個布爾值殉了,表示該值是否為Set的成員。 -
clear()
:清除所有成員拟枚,沒有返回值薪铜。
-
let a = new Set();
a.add(1).add(2); // a => Set(2) {1, 2}
a.has(2); // true
a.has(3); // false
a.delete(2); // true a => Set(1) {1}
a.clear(); // a => Set(0) {}
數(shù)組去重:
let a = new Set([1,2,3,3,3,3]);
2.Set的應(yīng)用
數(shù)組去重:
// 方法1
[...new Set([1,2,3,4,4,4])]; // [1,2,3,4]
// 方法2
Array.from(new Set([1,2,3,4,4,4])); // [1,2,3,4]
遍歷和過濾:
let a = new Set([1,2,3,4]);
// map 遍歷操作
let b = new Set([...a].map(x =>x*2));// b => Set(4) {2,4,6,8}
// filter 過濾操作
let c = new Set([...a].filter(x =>(x%2) == 0)); // b => Set(2) {2,4}
獲取并集恩溅、交集和差集:
let a = new Set([1,2,3]);
let b = new Set([4,3,2]);
// 并集
let c1 = new Set([...a, ...b]); // Set {1,2,3,4}
// 交集
let c2 = new Set([...a].filter(x => b.has(x))); // set {2,3}
// 差集
let c3 = new Set([...a].filter(x => !b.has(x))); // set {1}
- 遍歷方法:
-
keys()
:返回鍵名的遍歷器隔箍。 -
values()
:返回鍵值的遍歷器。 -
entries()
:返回鍵值對的遍歷器脚乡。 -
forEach()
:使用回調(diào)函數(shù)遍歷每個成員蜒滩。
-
Set
遍歷順序是插入順序,當保存多個回調(diào)函數(shù)奶稠,只需按照順序調(diào)用俯艰。但由于Set
結(jié)構(gòu)沒有鍵名只有鍵值,所以keys()
和values()
是返回結(jié)果相同窒典。
let a = new Set(['a','b','c']);
for(let i of a.keys()){console.log(i)}; // 'a' 'b' 'c'
for(let i of a.values()){console.log(i)}; // 'a' 'b' 'c'
for(let i of a.entries()){console.log(i)};
// ['a','a'] ['b','b'] ['c','c']
并且 還可以使用for...of
直接遍歷Set
蟆炊。
let a = new Set(['a','b','c']);
for(let k of a){console.log(k)}; // 'a' 'b' 'c'
forEach
與數(shù)組相同,對每個成員執(zhí)行操作瀑志,且無返回值涩搓。
let a = new Set(['a','b','c']);
a.forEach((v,k) => console.log(k + ' : ' + v));
3. Map對象
由于傳統(tǒng)的JavaScript
對象只能用字符串當做鍵,給開發(fā)帶來很大限制劈猪,ES6增加Map
數(shù)據(jù)結(jié)構(gòu)昧甘,使得各種類型的值(包括對象)都可以作為鍵。
Map
結(jié)構(gòu)提供了“值—值”的對應(yīng)战得,是一種更完善的 Hash 結(jié)構(gòu)實現(xiàn)充边。 基礎(chǔ)使用:
let a = new Map();
let b = {name: 'leo' };
a.set(b,'my name'); // 添加值
a.get(b); // 獲取值
a.size; // 獲取總數(shù)
a.has(b); // 查詢是否存在
a.delete(b); // 刪除一個值
a.clear(); // 清空所有成員 無返回
注意:
- 傳入數(shù)組作為參數(shù),指定鍵值對的數(shù)組。
let a = new Map([
['name','leo'],
['age',18]
])
- 如果對同一個鍵多次賦值浇冰,后面的值將覆蓋前面的值贬媒。
let a = new Map();
a.set(1,'aaa').set(1,'bbb');
a.get(1); // 'bbb'
- 如果讀取一個未知的鍵,則返回
undefined
肘习。
new Map().get('abcdef'); // undefined
- 同樣的值的兩個實例际乘,在 Map 結(jié)構(gòu)中被視為兩個鍵。
let a = new Map();
let a1 = ['aaa'];
let a2 = ['aaa'];
a.set(a1,111).set(a2,222);
a.get(a1); // 111
a.get(a2); // 222
遍歷方法: Map 的遍歷順序就是插入順序漂佩。
-
keys()
:返回鍵名的遍歷器脖含。 -
values()
:返回鍵值的遍歷器。 -
entries()
:返回所有成員的遍歷器投蝉。 -
forEach()
:遍歷 Map 的所有成員养葵。
let a = new Map([
['name','leo'],
['age',18]
])
for (let i of a.keys()){...};
for (let i of a.values()){...};
for (let i of a.entries()){...};
a.forEach((v,k,m)=>{
console.log(`key:${k},value:${v},map:${m}`)
})
將Map結(jié)構(gòu)轉(zhuǎn)成數(shù)組結(jié)構(gòu):
let a = new Map([
['name','leo'],
['age',18]
])
let a1 = [...a.keys()]; // a1 => ["name", "age"]
let a2 = [...a.values()]; // a2 => ["leo", 18]
let a3 = [...a.entries()];// a3 => [['name','leo'], ['age',18]]
4. Map與其他數(shù)據(jù)結(jié)構(gòu)互相轉(zhuǎn)換
- Map 轉(zhuǎn) 數(shù)組
let a = new Map().set(true,1).set({f:2},['abc']);
[...a]; // [[true:1], [ {f:2},['abc'] ]]
- 數(shù)組 轉(zhuǎn) Map
let a = [ ['name','leo'], [1, 'hi' ]]
let b = new Map(a);
- Map 轉(zhuǎn) 對象 如果所有 Map 的鍵都是字符串,它可以無損地轉(zhuǎn)為對象瘩缆。
如果有非字符串的鍵名关拒,那么這個鍵名會被轉(zhuǎn)成字符串,再作為對象的鍵名咳榜。
function fun(s) {
let obj = Object.create(null);
for (let [k,v] of s) {
obj[k] = v;
}
return obj;
}
const a = new Map().set('yes', true).set('no', false);
fun(a)
// { yes: true, no: false }
- 對象 轉(zhuǎn) Map
function fun(obj) {
let a = new Map();
for (let k of Object.keys(obj)) {
a.set(k, obj[k]);
}
return a;
}
fun({yes: true, no: false})
// Map {"yes" => true, "no" => false}
- Map 轉(zhuǎn) JSON
(1)Map鍵名都是字符串夏醉,轉(zhuǎn)為對象JSON:
function fun (s) {
let obj = Object.create(null);
for (let [k,v] of s) {
obj[k] = v;
}
return JSON.stringify(obj)
}
let a = new Map().set('yes', true).set('no', false);
fun(a);
// '{"yes":true,"no":false}'
(2)Map鍵名有非字符串爽锥,轉(zhuǎn)為數(shù)組JSON:
function fun (map) {
return JSON.stringify([...map]);
}
let a = new Map().set(true, 7).set({foo: 3}, ['abc']);
fun(a)
// '[[true,7],[{"foo":3},["abc"]]]'
- JSON 轉(zhuǎn) Map
(1)所有鍵名都是字符串:
function fun (s) {
let strMap = new Map();
for (let k of Object.keys(s)) {
strMap.set(k, s[k]);
}
return strMap;
return JSON.parse(strMap);
}
fun('{"yes": true, "no": false}')
// Map {'yes' => true, 'no' => false}
(2)整個 JSON 就是一個數(shù)組涌韩,且每個數(shù)組成員本身,又是一個有兩個成員的數(shù)組:
function fun2(s) {
return new Map(JSON.parse(s));
}
fun2('[[true,7],[{"foo":3},["abc"]]]')
// Map {true => 7, Object {foo: 3} => ['abc']}