一.集合的作用與特點
集合包括 Set/WeakSet、Map/WeakMap,類似於 hash table。特點如下:
-
避免了對象用作 hash table 時的弊端(為了避免原型屬性,可能需要用
Object.create(null)來創建原型為null的空對象,而不是字面量{},因為{} === Object.create(Object.prototype)) -
消除了用戶數據和內置方法的衝突,不把數據作為屬性暴露出來,無法通過
.key或者[key]訪問數據,而且集合不會從原型鏈繼承key -
集合遍歷順序與插入順序相同(而且可以利用
for...of等迭代器相關的新特性),而 hash table 理論上遍歷順序應該是不確定的(取決於 hash 函數) -
支持
has()方法,用於包含性檢測,比 indexOf 更快
二.Set
unique 值集。語法如下:
// 創建,參數 iterable 可選
new Set(iterable)
// 增,value 可以是任意類型的
Set.prototype.add(value)
// 刪 | 清空
Set.prototype.delete(value)|Set.prototype.clear()
// 查
Set.prototype.has(value)
// 遍歷,callback(value, value, set)
Set.prototype.forEach(callbackFn[, thisArg])
// 獲取元素個數
Set.prototype.size
// 獲取各種迭代器,為了兼容 Map,Set 中 keys === values
set.keys()、set.values() 和 set.entries()
特點:
-
自動去重,重複值無法 add,但 2 個屬性相同的對象被認為是不重複的
-
1 行代碼完成數組去重:
Array.from(new Set(arr)) -
避免了用戶數據和內置方法的衝突,不把數據作為屬性暴露出來,無法通過
.key或者[key]訪問數據,而且集合不會從原型鏈繼承key
示例:
var set = new Set('12231');
// 自動去重
console.log(set); // Set {"1", "2", "3"}
// 重複值無法 add
set.add('1');
console.log(set); // Set {"1", "2", "3"}
set.add(1);
console.log(set); // Set {"1", "2", "3", 1}
set.add({a: 1});
// 不重複
set.add({a: 1});
console.log(set); // Set {"1", "2", "3", 1, Object {a: 1}, Object {a: 1}}
兩個屬性值完全相同的對象會被認為是不重複的(當然,兩個指向相同對象的引用是重複的),而且 Set 內部的 hash 函數不支持重寫(安全性考慮),無法改變這種行為
三.Map
鍵值對集。語法如下:
// 創建,參數 pairs 可選,pairs 可以是[[key, val], ]二維數組、現有 Map 等等
new Map(pairs)
// 增 | 改/刪 | 清空/查找/讀取
map.set(key, val)/map.delete(key)|map.clear()/map.has(key)/map.get(key)
// 遍歷,callback(value, key, set),注意參數順序
map.forEach(callback)
// 獲取元素個數
Map.prototype.size
// 獲取各種迭代器,遍歷鍵/值/鍵值對
map.keys()、map.values() 和 map.entries()
特點:key可以是任意類型,包括 Object(不像對象的key只能是 String 或者 Symbol)
示例:
var map = new Map([['a', 1], ['b', 2]]);
//!!! 注意參數順序
map.forEach((val, key, arr) => {
console.log(`val = ${val}, key = ${key}`);
});
// log print:
// val = 1, key = a
// val = 2, key = b
// val = objA, key = [object Object]
注意:map.forEach 參數順序為 callback(value, key, set),而不是與 Array.forEach 類似的 callback(key, value, set)
四.WeakSet/WeakMap
功能受限的弱引用集合。避免 Set/Map 強引用帶來的內存洩漏問題,比如set.add(domNode)之後domNode被remove了,gc 無法回收domNode對象,因為set是強引用,只有調用set.delete(domNode)後才能回收內存
特點:
-
WeakSet 只支持 new, add, delete, has
-
WeakMap 只支持 new, get, set, delete, has
-
WeakSet 的值和 WeakMap 的鍵必須是 Object
-
不支持迭代
-
gc 可以回收仍在使用中的 Weak 集裡的無效元素
P.S.第 3 條比較奇怪(可能是出於 gc 考慮)
總之,在可能存在內存洩漏的場景(比如頻繁 DOM 操作,複雜動畫等等),考慮採用弱集合
五.總結
1 行代碼完成數組去重,多少讓人有那麼點激動
手捏數據結構的日子正在慢慢過去,底層建築正在完善
參考資料
- 《ES6 in Depth》:InfoQ 中文站提供的免費電子書
暫無評論,快來發表你的看法吧