跳到主要內容
黯羽輕揚每天積累一點點

集合(set 和 map)_ES6 筆記 8

免費2016-05-21#JS#js collection#js set#es6 map#es6 set#js map#es6集合

1 行代碼完成數組去重,多少讓人有那麼點激動。

一.集合的作用與特點

集合包括 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)之後domNoderemove了,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 中文站提供的免費電子書

評論

暫無評論,快來發表你的看法吧

提交評論