Set
基本用法
Set类似数组,但是它的元素都是唯一的,没有重复值。
构造函数Set()
用来生成Set数据结构。
const s = new Set();
[2,3,4,55,55,3].forEach(x => s.add(x));
console.log(Array.from(s)); // [2,3,4,55];
可以通过add()
方法为Set结构添加成员.
函数Set()
可以接受一个数组或者具有iterable
接口的其他数据结构作为参数来初始化
- 可以利用Set去除数组重复成员
[...new Set(array)];
- 可以利用Set去除字符串中的重复字符
[...new Set('abababcc')].join(''); // 'abc'
向Set加入值的时候,不会发生类型转换,所以数值5
和字符串'5'
是两个不同的值。Set内部判断两个值是否不同所使用的算法是“Same-value-zero equality”,“Same-value-zero equality”类似于精确相等运算符(===
),两者的区别是 Set 加入值时认为NaN
等于自身,而精确相等运算符(===
)认为NaN
不等于自身。
const s = new Set();
const a = NaN;
const b = NaN;
s.add(a);
s.add(b);
console.log(a === b); // false
console.log(Array.from(s)); // [NaN]
当添加的元素是对象时,在Set内部,对象总是不相等的。
const s = new Set();
s.add({});
s.add({});
console.log(Array.from(s)); // [{},{}]
console.log(s.size); // 2
Set实例的属性和方法
属性
Set.prototype.constructor
:构造函数,默认是Set()
Set.prototype.size
:返回Set
实例的成员总数
操作方法
Set.prototype.add(value)
:添加某个值,返回Set结构本身Set.prototype.delete(value)
:删除某个值,返回一个布尔值,表示是否删除成功Set.prototype.has(value)
:返回一个布尔值,表示是否有Set
成员Set.prototype.clear()
:清除所有成员,没有返回值Array.from()
可以将Set结构转换为数组
遍历操作
Set.prototype.keys()
:返回键名的遍历器Set.prototype.values()
:返回键值的遍历器Set.prototype.entries()
:返回键值对的遍历器Set.prototype.forEach()
:返回回调函数遍历每个成员
Set结构默认是可遍历的,默认遍历的是values()
.
WeakSet
基本用法
WeakSet 结构和 Set 类似,也是不重复的值的集合。
WeakSet 与 Set的区别
- WeakSet成员只能是对象,而不能是其他类型的值。
- WeakSet中的对象都是弱引用,垃圾回收机制不考虑WeakSet对这个对象的引用。
WeakSet适合临时存放一组对象,以后存放跟对象绑定的信息。
WeakSet实例的属性和方法
WeakSet是一个构造函数,可以使用new
命令创建WeakSet数据结构
const ws = new WeakSet();
这里可以接受任何具有Iterable
接口的对象作为参数,还需要具有Iterable
接口的对象的成员只能是对象。
const ws = new WeakSet([[1, 2], [2, 3]]);
console.log(ws); // {[1, 2], [2, 3]}
const ws1 = new WeakSet([1, 2]);
console.log(ws1); // ERROR TypeError: Invalid value used in weak set
方法
WeakSet.prototype.add(value)
:向WeakSet实例添加一个新成员WeakSet.prototype.delete(value)
:清除WeakSet实例的指定成员WeakSet.prototype.has(value)
:返回一个布尔值,表示WeakSet实例是否有这个值
需要注意:WeakSet没有
size
和forEach
属性
Map
基本用法
Map数据结构类似于对象(键值对的集合),但是Map的‘键’不限于字符串,各种类型的值(包括对象)都可以当作键。Object提供了‘字符串-值’的对应,Map提供了‘值-值’的对应,是一种更完善的Hash结构实现。
需要注意:
- 对同一个键多次赋值,后面的值将覆盖前面的值
const map = new Map();
map.set(1,'aaa').set(1,'bbb');
console.log(map.get(1)); // 'bbb'
- 读取一个未知的键,返回
undefined
.
console.log(new Map().get('abc')); // undefined
- 只有同一个对象的引用,Map结构才将其看作同一个键
const map = new Map();
map.set(['a'], 123);
map.get(['a']); // undefined
这里的set
和get
方法,看上去是针对同一个键,但是实际上是两个不同的数组实例,内存地址是不一样的,所有get
方法无法读取这个键,从而返回undefined
.
Map的键实际是和内存地址绑定的,只要内存地址不一样,就看做为两个键
Map的键为简的类型的值时,只要两个值严格相等,就看做为一个键
undefined
和null
也是两个不同的键
NaN
不严格等于自身,但是Map看做为同一个键
实例的属性和方法
属性
size
属性返回Map结构的成员总数
操作方法
Map.prototype.set(key.value)
:设置键名key
对应的键值value
,然后返回整个Map结构,如果key
已经有了,则键值会被更新Map.prototype.get(key)
:获取key
对应的键值,如果找不到,则返回undefined
.Map.prototype.has(key)
:返回一个布尔值,表示这个键是否在当前的Map对象中Map.prototype.delete(key)
:根据键key
删除,返回布尔值,表示是否删除成功Map.prototype.clear()
:清除Map实例的所有成员
遍历方法
Map.prototype.keys()
:返回键名的遍历器Map.prototype.values()
:返回键值的遍历器Map.prototype.entries()
:返回所有成员的遍历器Map.prototype.forEach()
:遍历Map的所有成员
Map结构的默认遍历器是entries()
与其他数据结构相互转换
- Map转换为数组
使用扩展运算符快速转为数组
const map = new Map().set(true, 7).set({foo:3},['abc']);
[...map]; // [[true,7],[{foo:3},['abc']]]
- 数组转为Map
将数组传入Map构造函数就可以了
const arr = [[true,7],[{foo:3},['abc']]];
const map = new Map(arr);
- Map转为对象
当Map的键都是字符串,则无损转为对象
当Map的键有非字符串,那么这个键名会转为字符串,再作为对象的键名
- 对象转为Map
function objToStrMap(obj){
const strMap = new Map();
for (const k of Object.keys(obj)){
strMap.set(k,obj[k]);
}
return strMap;
}
WeakMap
基本用法
WeakMap和Map的区别
- WeakMap只接受对象作为键名(
null
除外),不接受其他类型的值作为键名 - WeakMap的键名所指向的对象,不计入垃圾回收机制
方法
get()
set()
has()
delete()
WeakMap只有上面这四个方法可用。
用途
WeakMap应用的典型场合就是DOM节点作为键名。
let element = document.getElementById('logo');
lt weakMap = new WeakMap();
weakMap.set(element,{timesClicked:0});
element.addEventListener('click',function(){
let logoData = weakMap.get(element);
logoData.timesClicked++;
},false);
上面代码中,变量element
是DOM节点,每当有click
事件发生,就更新一下状态。将这个状态作为键值放在 WeakMap 里,对应的键名就是element
。一旦这个 DOM 节点删除,该状态就会自动消失,不存在内存泄漏风险。
备注:本文是自己学习阮一峰老师的《ECMAScript 6 入门》所做的笔记,大部分例子来源于此书。