ES6 提供了新的數據結構 Set
。它相似於數組,可是成員的值都是惟一的,沒有重複的值。
Set
自己是一個構造函數,用來生成 Set 數據結構。數組
const setArr = new Set();
[1,2,3,4,2,2,3,4].forEach(x => setArr.add(x));
for (let i of setArr) {
console.log(i);
}
// 1,2,3,4
複製代碼
Set
函數能夠接受一個數組(或者具備 iterable
接口的其餘數據結構)做爲參數,用來初始化。 特色:bash
Set
加入值的時候,不會發生類型轉換,因此4和"4"是兩個不一樣的值。// 以數組爲參數
const set = new Set([1, 2, 3, 4, 4, '4'])
[...set] // [1, 2, 3, 4, '4']
set.size // 5
// 一個相似數組的帶 iterable 接口的對象
const set = new Set(document.querySelectorAll('div'))
複製代碼
將Set
結構轉換成數組有兩個簡單的方法數據結構
[...set] // [1, 2, 3, 4, '4']
Array.from(set) // [1, 2, 3, 4, '4']
複製代碼
Set
結構的實例有如下屬性。函數
Set.prototype.constructor
:構造函數,默認就是Set
函數。Set.prototype.size
:返回Set
實例的成員總數。Set
實例的方法分爲兩大類:操做方法(用於操做數據)和遍歷方法(用於遍歷成員)。ui
add(value)
:添加某個值,返回 Set
結構自己。delete(value)
:刪除某個值,返回一個布爾值,表示刪除是否成功。has(value)
:返回一個布爾值,表示該值是否爲Set
的成員。clear()
:清除全部成員,沒有返回值。const s = new Set()
s.add(1).add(2).add(2)
s.size // 2
s.has(1) // true
s.has(2) // true
s.has(3) // false
s.delete(2)
s.size // 1
s.has(2) // false
複製代碼
keys()
:返回鍵名的遍歷器values()
:返回鍵值的遍歷器entries()
:返回鍵值對的遍歷器forEach()
:使用回調函數遍歷每一個成員keys
方法、values
方法、entries
方法返回的都是遍歷器對象。因爲 Set
結構沒有鍵名,只有鍵值(或者說鍵名和鍵值是同一個值),因此keys
方法和values
方法的行爲徹底一致。this
const set = new Set(['a', 'b', 'c']);
for (let item of set.keys()) {
console.log(item);
}
// a
// b
// c
for (let item of set.values()) {
console.log(item);
}
// a
// b
// c
for (let item of set.entries()) {
console.log(item);
}
// ["a", "a"]
// ["b", "b"]
// ["c", "c"]
複製代碼
對象結構 在使用這個幾個方法的時候相似,但有必定區別spa
const obj = { 1: 'a', 2: 'b', 3: 'c' }
for (let item of Object.keys(obj)) {
console.log(item);
}
// 1
// 2
// 3
for (let item of Object.values(obj)) {
console.log(item);
}
// a
// b
// c
for (let item of Object.entries(obj)) {
console.log(item);
}
// [1, "a"]
// [2, "b"]
// [3, "c"]
複製代碼
Set
結構的實例默承認遍歷,它的默認遍歷器生成函數就是它的values
方法。
這意味着,能夠省略values
方法,直接用for...of
循環遍歷 Set
。prototype
for (let i of set) {
console.log(i)
}
// a
// b
// c
複製代碼
forEach()
: Set 結構的實例與數組同樣,也擁有forEach方法,用於對每一個成員執行某種操做,沒有返回值。
不過key
和value
是同一個code
set.forEach((value, key) => console.log(key + ' : ' + value))
// a: a
// b: b
// c: c
複製代碼
遍歷的應用對象
let a = new Set([1, 2, 3]);
let b = new Set([4, 3, 2]);
// 並集
let union = new Set([...a, ...b]);
// Set {1, 2, 3, 4}
// 交集
let intersect = new Set([...a].filter(x => b.has(x)));
// set {2, 3}
// 差集
let difference = new Set([...union].filter(x => !intersect.has(x)));
// Set {1}
複製代碼
若是想在遍歷操做中,同步改變原來的 Set 結構,目前沒有直接的方法,但有兩種變通方法。
// 方法一
let set = new Set([1, 2, 3]);
set = new Set([...set].map(val => val * 2));
// set的值是2, 4, 6
// 方法二
let set = new Set([1, 2, 3]);
set = new Set(Array.from(set, val => val * 2));
// set的值是2, 4, 6
複製代碼
WeakSet 結構與 Set 相似,也是不重複的值的集合。可是,它與 Set 有兩個區別。
(1):WeakSet 能夠接受數組和相似數組的對象做爲參數。該數組的全部成員都會自動成爲WeakSet的實例對象的成員。數組成員只能是對象,不能是其餘類型的值。不然報錯。
const a = [[1, 2], [3, 4], {a: 1}]
const ws = new WeakSet(a)
// WeakSet {[1, 2], [3, 4]}
const b = [1, 2, [1,2]]
new WeakSet(b) // Uncaught TypeError: Invalid value used in weak set
複製代碼
(2):WeakSet 中的對象都是弱引用,即垃圾回收機制不考慮 WeakSet 對該對象的引用,也就是說,若是其餘對象都再也不引用該對象,那麼垃圾回收機制會自動回收該對象所佔用的內存,不考慮該對象還存在於 WeakSet 之中。
一個常規的對象本質應該是鍵值對的合集(即Hash結構)。它的鍵應該是一個字符串。 可是有時候須要使用其餘類型好比對象來作 鍵值對的 鍵。 因而就有了Map
結構
const data = {};
const element = document.getElementsByTagName('div')
data[element] = 'div';
data[element] // "div"
data['[object HTMLCollection]'] // "div"
// {[object HTMLCollection]: "div"}
const elementSpan = document.getElementsByTagName('span')
data[elementSpan] // "div"
複製代碼
element
被轉化成了'[object HTMLCollection]'
只是個字符串。 並不能達到經過element
取到值的效果。可是,使用Map
結構能夠。 Map
結構與對象很類似也是鍵值對, 但Map
的鍵能夠不是字符串,能夠是各類類型的值(包括對象)。若是你須要「鍵值對」的數據結構,Map
比 Object
更合適。
const dataMap = new Map()
dataMap.set(element, 'div')
dataMap.get(element) // div
// has,delete
dataMap.has(element) // true
dataMap.delete(element) // true
dataMap.has(element) // false
複製代碼
以上 new Map()
實例對象爲一個Map
結構,提供了set
、get
、has
、delete
幾個方法。輕鬆了實現了增刪改查。 構造函數Map
能夠接受一個數組做爲參數。
const map = new Map([ ['key1', 'value1'], ['key2', 'value2'] ])
複製代碼
任何具備 Iterator 接口、且每一個成員都是一個雙元素的數組的數據結構均可以看成Map構造函數的參數。如:數組,Set
結構, Map
結構。
const set = new Set([['a', 1],['b', 2]]);
const m1 = new Map(set);
m1.get('a') // 1
const m2 = new Map([['c', 3]]);
const m3 = new Map(m2);
m3.get('c') // 3
複製代碼
注意:只有對同一個對象的引用,Map 結構纔將其視爲同一個鍵。
const k1 = {a: 1 }
const k2 = {a: 1 }
const map = new Map()
map.set(k1, 111)
map.get(k2) // undefined
map.set(k2, 222)
map.get(k1) // 111
map.get(k2) // 222
複製代碼
由於即使值相同,可是兩個對象內存地址是不同的。
若是 Map 的鍵是一個簡單類型的值(數字、字符串、布爾值),則只要兩個值嚴格相等,Map 將其視爲一個鍵,好比0和-0就是一個鍵。
set
方法設置鍵名key對應的鍵值爲value
,而後返回整個 Map
結構。若是key
已經有值,則鍵值會被更新,不然就新生成該鍵。get
方法讀取key
對應的鍵值,若是找不到key
,返回undefined
。Map
結構的成員總數。has
方法返回一個布爾值,表示某個鍵是否在當前 Map
對象之中。delete
方法刪除某個鍵,返回true
。若是刪除失敗,返回false
。clear
方法清除全部成員,沒有返回值。const map = new Map();
// 能夠採用鏈式寫法。
map.set('a', 1).set('b', 2)
map.size // 2
map.get('b') // 2
map.set('b', 222)
map.get('b') // 222
map.get('c') // undefined
map.has('b') // true
map.delete('b') // true
map.has('b') // false
map.clear()
map.size // 0
複製代碼
keys()
:返回鍵名的遍歷器values()
:返回鍵值的遍歷器entries()
:返回鍵值對的遍歷器forEach()
:使用回調函數遍歷每一個成員須要特別注意的是,Map 的遍歷順序就是插入順序。
const map = new Map([['a', 1], ['b', 2]]);
for (let key of map.keys()) {
console.log(key);
}
// "a"
// "b"
for (let value of map.values()) {
console.log(value);
}
// 1
// 2
for (let item of map.entries()) {
console.log(item);
}
// ["a", 1]
// ["b", 2]
// 或者
for (let [key, value] of map.entries()) {
console.log(key, value);
}
// "a" 1
// "b" 2
// 等同於使用map.entries()
for (let [key, value] of map) {
console.log(key, value);
}
// "a" 1
// "b" 2
複製代碼
(1)Map 與數組的互換
const arr1 = [[{'k1': 11}, 11 ],['a', 1]]
const map = new Map(arr1)
[...map] // [[{'k1': 11}, 11 ],['a', 1]]
Array.from(map) // [[{'k1': 11}, 11 ],['a', 1]]
複製代碼
(2) Map 與對象的互換
若是全部 Map 的鍵都是字符串,它能夠轉爲對象。
const obj1 = { a:1, b:2 }
const obj2 = {}
const map = new Map()
for(let key of Object.keys(obj1)) {
map.set(key, obj1[key])
}
console.log(map) // Map(2) {"a" => 1, "b" => 2}
for (let [key,value] of map) {
obj2[key] = value
}
console.log(obj2) // {a: 1, b: 2}
複製代碼
(3) JSON 要轉換成 Map 能夠先轉換成數組或者對象,而後再轉換。
WeakMap
結構與Map
結構相似,也是用於生成鍵值對的集合。
const k1 = [1, 2, 3];
const k2 = [4, 5, 6];
const wm2 = new WeakMap([[k1, 'foo'], [k2, 'bar']]);
wm2.get(k2) // "bar"
複製代碼
const map = new WeakMap();
map.set(1, 2)
// TypeError: 1 is not an object!
複製代碼
WeakMap
與 Map
類似但有兩個區別:
WeakMap 應用的典型場合就是 DOM 節點做爲鍵名。 WeakMap 的另外一個用處是部署私有屬性。
const _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()
複製代碼
習題: 一· 求set 的值
let arr1 = [1, 2, 3, '3', 2]
const set = new Set(arr1)
複製代碼
二. 求遍歷的輸出
for (let [key, value] of set.entries()) {
console.log(key === value)
}
複製代碼
三. set 轉換數成數組
四. 求 data[obj1],
const obj1 = { a: 1}
const obj2 = { b: 2}
const data = {}
data[obj1] = 11
data[obj2] = 22
// 求 data[obj1]
複製代碼
五. 1.求 map.get({a: 1}), 2.若是 map 要轉換成其餘結果,應該是對象仍是數組
const map = new Map()
map.set({a: 1}, 111)
map.get({a: 1})
複製代碼