map & weakMap
map是一个个key&value的键值对,与object的不同是map的键可以是任何类型。具体api
map api 文档
weakmap api 文档
为什么很少人用
- map与set更多的可看为是object和array的扩展,抛开object格式的key与数组去重这些基本功能外,与object和array是很相似的。
- 是因为目前国内大部分用vue2,而vue2的基础definePrototype并不支持监听map,所以无法在vue2中很好的应用
为什么现在要去学
- 因为目前js在承担的更多的责任,比如用node写服务层,在对大量数据进行数据聚合时,对数据结构的性能有较高要求,理解不同数据结构的优劣更能提升效率
- 因为vue3将从definePrototype过渡到proxy,而proxy可以很好的用作map的监听,故而vue3支持了map和set的绑定功能,在vue3马上发布之际,学习map是不错的选择。
对赋值速度的比较
这里通过函数比较map与array在赋值方便的速度比较
// 获取函数运行时间
function getTime(fn, ...args) {
const now = Date.now()
const result = fn.apply(this, args)
console.log(`用时:${Date.now() - now}毫秒,结果:${result}`)
}
const obj = {};
getTime(() => {
console.log('Object 赋值 耗时');
for (let i = 0; i < 500000; i++) {
obj['key_'+i] = i;
}
});
const map = new Map();
getTime(() => {
console.log('Map 赋值 耗时');
for (let i = 0; i < 500000; i++) {
map.set('key_'+i, i);
}
});
我们通过更改赋值数量的大小,可以看出,在数值较小时,map保持一定优势,当数值超过100000时,map的赋值速度会开始下降
1000条数据 object: 2ms map: 0ms
10000条数据 object: 9ms map: 5ms
100000条数据 object: 88ms map: 51ms
500000条数据 object: 367ms map: 286ms
1000000条数据 object: 905ms map: 899ms
2000000条数据 object: 2151ms map: 3117ms
3000000条数据 object: 3781ms map: 6919ms
之后map的效率会呈指数降低
- 得出结论:map在一百万条数据前的赋值效率表现更好,但超过一百万条,效率呈指数降低。
tips: 两种数据结构在赋值方面的性能表现可以用于在对大量数据进行数组操作时数据结构选择的依据。如在数据超过一百万条时,性能出现滑坡,可考虑object替换map。
对解析速度的比较
getTime(() => {
console.log('Object 键值cover100% 耗时');
let result = 0;
for (let i = 0; i < length; i++) {
result += obj['key_'+(i + length)] || 0;
}
return result;
});
getTime(() => {
console.log('Map 键值cover100% 耗时');
let result = 0;
for (let i = 0; i < length; i++) {
result += map.get('key_'+ (i + length)) || 0;
}
return result;
});
分为三种样本测试解析速度。
- 当键值100%匹配时,解析速度相差无忌,map稍微领先
- 当键值50%匹配时,解析速度map领先
- 当键值0%匹配时,解析速度map领先
故,如果是非字典,枚举类的需求,比如一个缓存空间,需要频繁比对键值是否存在,存在取出,不存在放入空间这种操作时,用map更有利。
缺点,map本身有自己的结构,不能被Object.defineProperty,所以在vue2里运用较差,目前只在静态数据中使用过。但vue3运用proxy后会支持对map与set的应用
Map & WeakMap
WeakMap本身是一种弱引用的Map,他仅支持键值为对象的情况,而且不可被枚举。既然有着键值必须为对象,且无法遍历等种种问题,那他存在的意义是什么呢?
这涉及到js的垃圾回收机制,对于js而言,一个没有再继续被引用的变量的内存将会被回收,而被放入Map里的键值对,会一直被Map内部的两个数组引用,从而导致垃圾内存回收失败。而WeakMap是弱引用,即当键值对象在没有其他引用时,键值对象就可以被回收。
代码说明
const a = new Map();
function haha() {
console.log('start')
for (var i = 0; i < 1000000; i++) {
(function() {
const b = {a: 1}
a.set(b, 'aaaac')
})()
}
console.log('end')
}
在for循环中使用闭包暂存声明b,b在闭包结束后再无引用而直接被回收,但是如果放在Map里,则会被强引用而阻止垃圾回收,把Map换成weakMap,通过chrome检查内存可理解这个问题。
举个例子,在一个带分页table列表里,每一列的查看功能需要向后端请求数据并显示,我们需要对这个点击操作做缓存,但又需要当翻页后或者离开页面,即列表里的数据消失时就清除掉这些缓存,方式缓存过多造成内存浪费。那么这个时候我们用weakMap就是最好的选择。
网友评论