Map、WeakMap的区别

一、Map

1、基本API

使用new关键字和Map构造函数可以创建一个空映射

const m = new Map()

如果想在创建的同时初始化实例,可以给Map构造函数传入一个可迭代的对象,需要包含键值对数组。可迭代对象的每个键值对都会按照迭代顺序插入到新映射实例中 。

初始化之后,可使用set()方法再添加键值对。使用get()和has()进行查询,通过size属性获得映射中键值对的数量,还可以使用delete()和clear()删除值。

   const m = new Map()
   console.log(m.size)  //0
   m.set("key1","val1")
    .set("key2","val2") 
   console.log(m.has("key1")) //true
   console.log(m.get("key1")) //val1
   m.delete("key1")  
   console.log(m.size) //1
   m.clear()
   console.log(m.size) //0

与Object只能使用数值、字符串或符号作为键不同,Map可以使用任何JavaScript数据类型作为键

2、顺序与迭代

与Object类型的一个主要差异是,Map实例会维护键值对的插入顺序,因此可以根据插入顺序执行迭代操作

映射实例可以提供一个迭代器(Iterator),能以插入顺序生成[key,value]形式的数组。可以通过entries()方法(或者Symbol.iterator属性,它应用entries())取得这个迭代器

  const m  = new Map([
    ["key1","val1"],
    ["key2","val2"],
    ["key3","val3"]
  ])
  console.log(m.entries === m[Symbol.iterator]) //true
  for(let pair of m.entries()){
    console.log(pair)
  }  //["key1","val1"]
    // ["key2","val2"]
    // ["key3","val3"]

键和值在迭代器遍历时是可以修改的,但映射内部的引用则无法修改 

  const m  = new Map([
    ["key1","val1"]
  ])
  //作为键的字符串原始值是不能修改的
  for(let key of m.keys()){
    key = "newKey"
    console.log(key)  //newKey
    console.log(m.get("key1")) //val1
  }
   const keyobj = {id:1}
   const m1 = new Map([
     [keyobj,"val1"]
   ])
   //修改了作为键的对象的属性,但对象在映射内部仍然存在相同的值
   for(let key of m1.keys()){
     key.id ="new"
     console.log(key)      //{id:'new'}
     console.log(m1.get(keyobj))// val1
   }
   console.log(keyobj)    //{id:'new'}

3、对比Object和Map()

主要差别在于内存和性能,对象和映射之间存在显著差别

  • 内存占用

Object和Map的 工程级实现在不同浏览器中存在明显差异,但存储单个键值对所占用的内存数量都会随键的数量线性增加。给定固定大小的内存,Map大约可以比Object多存储50%的键值对。

  • 插入性能

消耗大致相当,Map在某些浏览器会快一些,若涉及大量代码,Map的性能更加

  • 查找速度 

与插入不同,在大型Object和Map中查找键值对的性能差异极小,但如果只包含少量键值对,则Object更快。在把Object当数组使用时,浏览器引擎可以进行优化,把内存中使用更高效的布局

  • 删除性能 

Map的delete()操作快!

二、WeakMap

弱映射,是一种增强的键值对存储机制。(weak描述的是JavaScript垃圾回收程序对待“若映射”中键的方式) 

1、基本API

 const wm = new WeakMap()

弱映射中的键只能是Object或者继承自Object的类型,尝试使用非对象设置键会抛出TypeError。值的类型没有限制

初始化之后可以使用set()再添加键值对,使用get()和has()查询,还可以使用delete()删除

2、弱键

这些键不属于正式的引用,不会阻止垃圾回收,值并不是。只要键存在,键值对就好存在于映射中,并被当做值的引用,因此不会被当做垃圾回收

 const wm = new WeakMap()
 wm.set({},"val")

set()方法初始化了一个新对象并将它用作一个字符串的键。因为没有指向这个对象的其他引用,所以当这行代码执行完成后,这个对象就好被当做垃圾回收。然后这个键值对就从弱映射中消失了,然后形成一个空映射

 const wm = new WeakMap()
 const container = {
   key : {}
 }
 wm.set(container.key,"val")
function removeReference(){
  container.key = null
}

container维护这一个对弱映射键的引用,因此这个对象键不会成为垃圾对象

3、 不可迭代键

因为WeakMap中键值对任何时候都可能被销毁,所以没必要提供迭代其键值对的能力。WeakMap实例之所以限制只能使用对象作为键,是为了保证只有通过键对象的引用才能取得值。如果允许原始值,那就没办法区分初始化时使用的字符串字面量和初始化之后使用的一个相对的字符串了。

你可能感兴趣的:(前端,javascript)