集合(set和map)_ES6笔记8

一.集合的作用与特点

集合包括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中文站提供的免费电子书

集合(set和map)_ES6笔记8》上有2条评论

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*

code