js Map 原理

这段话是我抄的 感觉不太对
众所周知 map 是个hash 表,但js的map 不是,js的map很烂,是两个数组组成的,Map api共用了两个数组(一个存放key,一个存放value)。给Map set值时会同时将key和value添加到这两个数组的末尾。从而使得key和value的索引在两个数组中相对应。当从Map取值时,需要遍历所有的key,然后使用索引从存储值的数组中检索出相应的value。这个实现的缺点很大,首先是赋值和搜索的时间复杂度为O(n),其次是可能导致内存溢出,因为数组会一直保存每个键值引用,即便是引用早已离开作用域,垃圾回收器也无法回收这些内存。

测试 Map 和 Object的效率

空数据对照(删除了js代码)
image.png

MAP

  1. let map = new Map()
  2. let person = {name:'gromy',age:0}
  3. let sum = 100000
  4. let start = Date.now()
  5. for(let i = 0;i<sum;i++){
  6. let k = person.name+i
  7. let val = Object.assign({},person)
  8. val.age = i
  9. map.set(k,val)
  10. }
  11. console.log('add',Date.now() - start)
  12. setTimeout(()=>{
  13. let start = Date.now()
  14. for(let i = 0;i<sum;i++){
  15. let k = person.name+i
  16. map.get(k)
  17. }
  18. console.log('get',Date.now() - start)
  19. },200)
  20. setTimeout(()=>{
  21. let start = Date.now()
  22. map.forEach((k,v)=>{})
  23. console.log('forEach',Date.now() - start)
  24. },400)

add

  1. let start = Date.now()
  2. for(let i = 0;i<10000;i++){
  3. let k = person.name+i
  4. let val = Object.assign({},person)
  5. val.age = i
  6. map.set(k,val)
  7. }
  8. console.log(Date.now() - start)

image.png
增大为100000

  1. for(let i = 0;i<100000;i++){
  2. let k = person.name+i
  3. let val = Object.assign({},person)
  4. val.age = i
  5. map.set(k,val)
  6. }

image.png

get

  1. setTimeout(()=>{
  2. let start = Date.now()
  3. for(let i = 0;i<sum;i++){
  4. let k = person.name+i
  5. map.get(k)
  6. }
  7. console.log(Date.now() - start)let start1 = Date.now()
  8. let val = map.get('gromy9999')
  9. console.log(Date.now() - start1,val)

sum = 100000时
时间消耗
image.png

遍历

一起执行一下
image.png
这里第一次事件循环结束注册 两个 timeout 事件,还没执行
image.png

结论

set 的时候占用内存,get也会占用内存,遍历不会(heap)
时间
image.png

Object

  1. let obj = {}
  2. let person = {name:'gromy',age:0}
  3. let sum = 100000
  4. let start = Date.now()
  5. for(let i = 0;i<sum;i++){
  6. let k = person.name+i
  7. let val = Object.assign({},person)
  8. val.age = i
  9. obj[k]=val
  10. }
  11. console.log('add',Date.now() - start)
  12. setTimeout(()=>{
  13. let start = Date.now()
  14. for(let i = 0;i<sum;i++){
  15. let k = person.name+i
  16. obj[k]
  17. }
  18. console.log('get',Date.now() - start)
  19. },200)
  20. setTimeout(()=>{
  21. let start = Date.now()
  22. for(k in obj){
  23. obj[k]
  24. }
  25. console.log('forEach',Date.now() - start)
  26. },400)

image.png
时间占用
image.png


结论

内存:Map > Object
时间:Object > Map

录制一个15s 的

map

image.png
可以看到8s 左右在一次 gc 后内存被释放了

object

image.png
10s 左右被释放

weakMap

  1. let wm = new WeakMap()
  2. let person = { name: 'gromy', age: 0 }
  3. let sum = 100000
  4. setTimeout(() => {
  5. let start = Date.now()
  6. for (let i = 0; i < sum; i++) {
  7. let val = Object.assign({}, person)
  8. val.age = i
  9. wm.set(val, val)
  10. }
  11. console.log('add', Date.now() - start)
  12. }, 1000)
  13. setTimeout(() => {
  14. let start = Date.now()
  15. for (let i = 0; i < sum; i++) {
  16. let val = Object.assign({}, person)
  17. val.age = i
  18. wm.get(val)
  19. }
  20. console.log('get', Date.now() - start)
  21. }, 2000)

image.png
一样被释放了
所以 weakMap的优势?
看下时间,image.png
跟Map 一样