前言
Map、WeakMap、Set、WeakSet作为es6新增的引用数据类型,平常用的最多的无非使用Set去重,但对于Map、WeakMap、WeakSet的用法及应用场景都很模糊,这里通过综合红宝书及MDN文档从:简单用法、使用场景、区别。三方面记录一下这四种引用类型的使用和差异。
Map
Map:
es6
新增特性,是一种新的集合类型,一种“键/值”存储的对象。
初始化:可以创建的时候赋值,也可以通过它内置的API:set()方法进行添加键值对。举例: 初始化赋值。
const m1 = new Map([
['key1', 'value1'],
['key2', 'value2']
])
Map提供了很多方法简单举例:(增删查)
增:set()
set():赋值.
它
返回的是映射实例
,因此可以实现链式操作
m1.set(['key3', 'value3']).set(['key6', 'value6'])
删:delete(),clear()
delete()
移除对应的键的键值对。 存在相同键值的键值对都会被删除。
m1.delete(key)
clear()
移除Map对象中的所有元素
m1.clear()
查:get(),has()
get()
返回的是Map对象中对应键的值
m1.get(key)
has()
返回的是Map对象中是否存在对应的键 布尔值
举例:
const m2 = new Map([[]])
m2.has(undefined) //true
m2.get(undefined) //undefined
获取数量:size()
获取键值对数量
m1.size()
顺序与迭代:entries()
Map会维护键值对的插入顺序,因此可以根据插入顺序进行迭代.Map提供entries()来引用
Symbol.iterator
。 有图有真相:
提到这里Object是没有Symbol.iterator
的所以,不可使用迭代器。知识点:for of
和for in
的区别:链接
迭代键值:keys(), values()
keys()
MDN: 返回一个引用的
Iterator
对象。它包含按照顺序插入Map
对象中每个元素的key值.
values()
MDN: 返回一个新的
Iterator
对象。它包含按顺序插入Map
对象中每个元素的value值.
keys()和values()都是引用iterator对象,iterator的返回结果包含 value和done属性.这里注意keys和values使用next()后获取的值都是value
WeakMap(弱映射)
es6新增特性,也是一种新的集合类型。是Map的”兄弟“类型,其API也是Map的子集。
红宝书中定义:week-> ‘弱弱的拿着’
,意思是这些键不属于正式引用,不会被垃圾回收。我认为就像涉及到闭包一样,使用了引用值,因此只要键存在,就存在于映射中,对此不会被当作垃圾回收。
举例:
const wm = new WeekMap();
wm.set({}, 'val');
上面的代码中通过set()初始化一个键为空对象的,由于没有指向这个空对象的引用,对此这里会被当做垃圾回收。
通过下面这个例子就可以更能清楚“不是被正式的拿着,不会阻止垃圾回收”
const wm = new WeakMap();
const container = {
key: {}
}
wm.set(container.key, 'val');
function removeReference() {
container.key = null;
}
这里初始化的时候通过一个对于引用空对象的键名,是一个引用(指向container的key值)所以不会被当作垃圾回收。
而可以通过调用removeReference这个函数清空引用值,最后达到垃圾回收的效果。(闭包的解决方案之一也是将引用值设为null
)
提供的方法:
从WeakMap实例对象看到,并没有提供可迭代方法。也正因为‘weak
’,没有正式的引用。
其余方法的具体用法见:MDN
Set
ES6新增集合类型。Set中的元素只会出现一次,即 Set 中的元素是
唯一
的
增 add()
在
Set
对象尾部
添加一个元素。返回该Set
对象。返回的是集合实例,因此可以通过实现链式操作(Map的set()同理)
const s = new Set()
s.add('val1').add('val2').add('val3')
删 delete(), clear()
delete()
删除当前value值 返回值为布尔值
s.delete(value)
clear()
清空Set对象中的所有元素
s.clear()
查 has()
查询是否拥有当前value 返回值为布尔值
s.has(value)
WeakSet(弱集合)
WeakSet和Set和WeakMap和Map介绍相同,上面已经详细介绍过了。
其用法可以参考MDN
WeakMap的使用场景
1. 私有变量
之前我一篇文章也讲到过js的封装、继承、多态。和这里思路类似。
代码摘自红宝书:
const User = (() => {
const wm = new WeakMap();
class User {
constructor(id) {
this.idProperty = Symbol('id');
this.setId(id);
}
setPrivate(property, value) {
const privateMembers = wm.get(this) || {};
privateMembers[property] = value;
wm.set(this, privateMembers)
}
getProvate(property) {
return wm.get(this)[property]
}
setId(id) {
this.setPrivate(this.idProperty, id)
}
getId(id) {
return this.getProvate(this.idProperty)
}
}
return User
})()
const user = new User(123)
console.log(user.getId()) //123
user.setId(456)
console.log(user.getId()) //456
实现: 以对象实例为键,以私有成员的字典为值。通过上面方式:获取不到弱映射的键名,所以无法取得对应的值。最主要还是利用了Symbol对象。
2. DOM节点元数据
WeakMap实例不会阻止垃圾回收机制
,若想对一个DOM节点关联一些样式,那么我们将DOM节点设为键名,当节点被删除掉(引用地址为null
),那么这里就会采用垃圾回收机制,释放内存
。
Set的使用场景
1. 数组去重 es6拓展运算符配合new Set()
var arr = [1, 2, 3, 2, 1];
var result = [...new Set(arr)]
console.log(result) // [1, 2, 3]
2. 数组去重 Array.from配合new Set()
Array.from()
方法从一个类似数组或可迭代对象创建一个新的,浅拷贝
的数组实例。
var arr = [1, 2, 3, 2, 1];
var result = Array.from(new Set(arr))
console.log(result) // [1, 2, 3]
Map和Object的区别
- Map为体现
键值对
形式的数据结构(Map
可以支持任意JS数据类型
作为键名,而Object
只能是数值
、字符串
或者符号
) 内存占用
: 不同浏览器下情况不同,Map大约比Object多存储50%的键值对插入性能
: 插入速度都不会因为键值对的数量进行线性增加,但对于大量插入操作,Map的性能更佳。查找速度
: 如果是少量的键值对,Object的速度更快删除性能
: Map在大多数浏览器引擎中删除操作较快。
总结
- es6新增引用数据类型:Map、WeakMap、Set、WeakSet
- Map、WeakMap:
键值对
映射 - Set、WeakSet:
值
的集合 - 带有
weak
的 弱引用,不阻止
垃圾回收机制、不可迭代
- 对于WeakMap、WeakSet都可以在对DOM节点进行修饰时,作为存储类型。
往期js文章: