Set 是一種集合結構,特徵和數學中的一致,具備如下特徵:數組
但使用過程當中請注意如下幾點:數據結構
定義聚合和定義其餘數據結構同樣,其構造函數接受一個數組,集合或類數組對象初始化:函數
var set1 = new Set(); var set2 = new Set([1,2,3,3,4,4,5]); console.log(set1); //Set(0) {} console.log(set2); //Set(5) {1, 2, 3, 4, 5}
Set結構具備如下屬性和方法,因爲和數組方法基本一致,不細細列舉this
Set的默認遍歷器遍歷的是值:prototype
Set.prototype[Symbol.iterator] === Set.prototype.values; //true
集合運算:code
var a = new Set([1,2,3]); var b = new Set([2,4,5]); var union = new Set([...a, ...b]); //[1,2,3,4,5]
var a = new Set([1,2,3]); var b = new Set([2,4,5]); var intersect = new Set([...a].filter(item => b.has(item))); //[2]
var a = new Set([1,2,3]); var b = new Set([2,4,5]); var diffsect = new Set([...a].filter(item => !b.has(item))); //[1,3]
WeakSet 和 Set相似,可是具備如下區別:對象
定義WeakSet和定義其餘數據結構同樣,其構造函數接受一個數組,集合或類數組對象初始化:three
var set1 = new WeakSet(); var set2 = new WeakSet([[1,2],[3,3],[4,4,5]]); console.log(set1); //WeakSet(0) {} console.log(set2); //WeakSet {(2) [1, 2], (2) [3, 3], (3) [4, 4, 5]}
WeakSet 沒有 size 屬性,有以下3個方法:內存
WeakSet 不能遍歷,它的做用是臨時存儲DOM節點,這樣沒必要擔憂內存泄漏:資源
//例 const foos = new WeakSet(); class Foo{ constructor(){ foos.add(this); } method(){ if(!foos.has(this)){ throw new TypeError(`"foo.prototype.method" is only called by object of Foo`); } console.log(`"Foo.prototype.method" has been called`); } } var obj = new Foo(); obj.method(); //Foo.prototype.method" has been called obj.method.call({}); //typeError: "foo.prototype.method" is only called by object of Foo
js 中的對象是鍵值對的集合,可是鍵只能是字符串其實並不方便。Map結構本質和對象同樣,只是鍵名可使用各類類型的值。若是這麼理解,那麼Map就是一種值-值對而不是鍵-值對,這一點相似hash結構:
var o = {name: "Bob"}; var map = new Map(); map.set(o, "hello"); console.log(map.get(o)); //"hello"
構造 Map 結構的構造函數接受數組,對象等類型做爲構造函數的參數:
var map = new Map([["name","Bob"], ["age", 12]]); map.get("name"); //"Bob" map.get("age"); //12
map具備以下屬性和方法:
var o = {name: "Bob"}; var map = new Map(); map.set(o, "hello"); console.log(map.get(o)); //"hello" map.set(o, "world"); //重複定義,覆蓋以前的定義 console.log(map.get(o)); //"world" console.log(map.get({name: "Bob"})); //undefined, 不一樣的對象引用不認爲是同一個對象 map.delete(o); //刪除對象屬性 o console.log(map.get(o)); //undefined
從上方的例子不難發現,不一樣的對象屬性對於 map 來講就是不一樣的,無論內部的內容是否一致。這和對象的 === 比較是同樣的道理,帶來的好處是咱們不用擔憂和會 map 原有屬性重名,而直接向 map 添加對象屬性便可。
注意 undefined,NaN和 null 也能夠做爲 map 的鍵名
var map = new Map(); map.set(undefined, 1); map.set(null, 2); map.set(NaN, 3); console.log(map.get(undefined)); //1 console.log(map.get(null)); //2 console.log(map.get(NaN)); //3
但使用過程當中請注意如下幾點:
map 的默認遍歷器是 entries()
Map.prototype[Symbol.iterator] === Map.prototype.entries; //true
另外這裏須要格外強調的是:
Set.prototype.has(value)
, WeakSet.prototype.has(value)
Map.prototype.has(key)
, WeakMap.prototype.has(key)
, Reflect.has(target, propertyKey)
Map解構轉換技巧:
var map = new Map([[1,'one'], [2, 'two'], [3, 'three']]); var keyArr = [...map.keys()]; //[1,2,3] var valueArr = [...map.values()]; //['one','two','three'] var entriesArr = [...map.entries()]; //[[1,'one'], [2, 'two'], [3, 'three']] var arr = [...map]; //[[1,'one'], [2, 'two'], [3, 'three']]
function map2arr(map){ var o = {}; for(let [key, value] of map.entries()){ if(typeof key === 'string'){ o[key] = value; } } return o; } var map = new Map([[1,'one'], [2, 'two'], ['three', 3], ['four', 4]]); map2arr(map); //Object {three: 3, four: 4}
var map = new Map([[1,'one'], [2, 'two'], ['three', 3], ['four', 4]]); JSON.stringify([...map]); //"[[1,"one"],[2,"two"],["three",3],["four",4]]"
WeakMap 和 map 相似,不過它只接受對象做爲鍵名,null除外。試想,若是對象 o 是一個 map的屬性,若是該對象被釋放了,那這個 map 屬性會致使內存溢出。解決這個問題就是使用 WeakMap:
var o = {name: "Bob"}; var map = new WeakMap(); map.set(o, 12); console.log(map.get(o)); //12 o = null; console.log(map.get(o)); //undefined
WeakMap的對象屬性名,不計入 GC,因此當對象不存在的時候,這個 weakmap 中相應的鍵值對就被刪除了。值得一提的是,代碼對於 map 能夠獲得同樣的輸出。那是由於最後一行至關於console.log(map.get(null))
, 咱們沒有定義 null 對應的值,因此獲得 undefined, 其實內存泄露的隱患依然存在:
var o = {name: "Bob"}; var map = new Map(); map.set(o, 12); console.log(map.get(o)); //12 o = null; console.log(map.size); //1
WeakMap 和 WeakSet 相似,因爲不計入 GC 回收機制,因此不支持遍歷操做,也不支持被清空,因此 WeakMap 只有如下 4 個方法,沒有 size 屬性: