跳至主要內容

16. Map

Harry Xiong大约 6 分钟Web 前端JavaScriptPromise 对象JS 异步async 与 await

Map

ES6提供Map数据结构,该对象类似于普通对象,也是键值对的集合,但是该对象的键不像普通对象那样只能用字符串作为键,而是可以使用各种类型的值(包括对象)来作为键

JS中的对象本质上是键值对的集合(Hash结构),但是传统上只能用字符串当作键,这就使得在使用JS对象的时候有很大的限制。也就是说,Object结构提供的是字符串与值相对应的键值对模式.而Map结构提供的是值与值相对应的键值对模式,相对来说更加的完善

16.1 用法

var m=new Map();
var o={a:1};
m.set(o,1);
/*
只能通过set()方法来设置值,最好通过变量来储存键,以便于获取,因为如果不通过变量获取就不是对同一个对象的引
用,会返回undefiend
*/
console.log(m.get({a:1}));//undefined
console.log(m.get(o));//1
console.log(m.o);//undefined
console.log(m[o]);//undefined
/*
    只能通过get()方法来获取到对应键的内容,不能通过点或[]来获取,因为该结构不是普通对象的结构,通过这两种    方式只能拿到普通对象键对应的值
*/
//也可以传入普通的数据类型
var m=new Map([
    ["name","孙悟空"],
    [{age:18},18]
])
console.log(m.get("name"));//"孙悟空"

注意:

  • 在直接通过结构赋值创建对象时,传入的参数需要是一个数组,同时数组中的每一个成员需要用一个二维数组括起来作为键值对

  • 如果Map实例的键是一个简单类型的值,则只要两个值严格相等,Map内部就会将其视为一个值,比如0和-0依然是一个值,而1与"1"就不是一个值。NaN虽然不等于自身,但是Map内部将其视为同一个值

16.2 属性与方法

16.2.1 size

Map类的实例有一个size属性,专门用来记录Set实例中的值的数量,返会Map实例成员的数量

16.2.2 get,delete,has与clear方法

  • get()方法为Map实例添加一个值,传入两个参数,分别代表键和值,返回实例对象本身,可以用作链式操作

  • delete()方法删除Map实例的某个值,删除成功返回true,删除失败返回false

  • has()方法判断Map实例中是否有某个值.有就返回true,没有返回false

  • clear()方法情况Map实例中的所有值,没有返回值

var m=new Map();
m.set("a",1);
m.set("b",2);

console.log(m);//Map(2) {"a" => 1, "b" => 2}
console.log(m.get("a"));//1

m.delete("a");
console.log(m.get("a"));//undefined

console.log(m.has("b"));//true

m.clear();
console.log(m);//Map(0){}

16.2.3 keys,values与entries方法

keys()方法返回装有Map实例的键名的数组,values()方法返回装有Map实例的键名值的数组,entries()方法返回装有Map实例的键名和键值的数组,这些方法与Set实例不同,都能得到不同的数组

16.2.4 forEach方法

Map实例的forEach()方法的用法与表现结果与数组的forEach()方法的表现结果一致,第一个参数是回调函数,第二个参数是回调函数中this的指向对象

var m=new Map([["a",1],["b",2],["c",3]]);
m.forEach(function(value,key){
    console.log(key,value)//a 1 b 2 c 3
})

**注意:**Map遍历的顺序就是插入顺序,遍历行为基本与Set一致

16.3 类型转换

16.3.1 与数组转换

  • Map转数组

    var m = new Map([["a", 1], ["b", 2], ["c", 3]]);
    console.log([...m]);//[Array(2), Array(2), Array(2)]
    /*
        结果为数组中包含三个二维数组,每个二维数组分别存有一个Map对象的成员
    */
    
    var m = new Map([[1, 2], [2, 4], [4, 8]]);
    Array.from(m);
    // 输出:[ [1, 2], [2, 4], [4, 8] ]
    
  • 数组转Map

    var m=new Map([["a",1],["b",2],["c",3]]);
    console.log(m);//Map(3) {"a" => 1, "b" => 2, "c" => 3}
    

16.3.2 与对象转换

  • Map转对象

    注:

    只有Map实例中所有的键都是字符串才能转为对象

    var m=new Map([["a",1],["b",2],["c",3]]);
    var obj={};
    for(var [key,value] of m){
        obj[key]=value;
    }
    console.log(obj);//{a: 1, b: 2, c: 3}
    
  • 对象转Map

    var m=new Map();
    var obj={a:1,b:2,c:3};
    /*
    for(var key in obj){
        m.set(key,obj[k]);
    }
    由于for...in的性能原因,改用for...of
    
    */
    for(var key of Object.keys(obj)){
        m.set(key,obj[key]);
    }
    
    console.log(m);//Map(3) {"a" => 1, "b" => 2, "c" => 3}
    

16.3.3 与JSON转换

  • Map转JSON Map转为JSON时分两种情况,如果Map的简明全是字符串就转换为JSON对象,如果键名有非字符串,就转换为JSON数组

    • Map=>JSON对象

      var m=new Map([["a",1],["b",2],["c",3]]);
      var obj={};
      for(var [key,value] of m){
          obj[key]=value;
      }
      var json=JSON.stringify(obj);//实质上时先转为对象再转为JSON
      console.log(json);
      
    • Map=>JSON数组

      var m=new Map([["a",1],["b",2],[{c:3},3]]);
      var json=JSON.stringify([...m]);//还是先转换为数组在转换为JSON
      console.log(json);
      
  • JSON转Map JSON转换为Map时,正常情况下所有的键名都会转为字符串,无论是不是对象,但是如果JSON整个是一个数组,且每一个数组成员本身都是一个二维数组,每个二维数组里面有两个成员,这样就能一一对应转换为Map。这往往是数组转为JSON的逆操作

    • 一般情况

      var json = '{"a":1,"b":2,"c":3}';
      var obj = JSON.parse(json);
      var m = new Map();
      for (var key of Object.keys(obj)) {
         m.set(key, obj[key]);
      }
      console.log(m);//Map(3) {"a" => 1, "b" => 2, "c" => 3}
      
    • 特殊情况

      var json='[[{"a":1},1],["b",2],["c",3]]';
      var m=new Map(JSON.parse(json));
      console.log(m);//Map(3) {{…} => 1, "b" => 2, "c" => 3}
      

16.4 WeakMap

WeakMap和Map的结果类似,也是一个类,也是用于生成键值对的集合,但是与Map依然有一些区别

区别:

  • WeakMap实例只接收对象作为键名(null除外),不能使用其它类型的值作为键名使用

  • WeakMap的键名指向的对象是弱引用,不会计入垃圾回收机制,同WeakSet一致

**注:**当我们想在某个对象上存储一些数据时,会形成对该对象的引用,从而让这个对象无法被回收,WeakMap就是为了解决这个问题而诞生的,它的键名都是弱引用,即垃圾回收机制不会将该对象的引用保留在内

var div = document.getElementsByTagName("div");
var w = new WeakMap();
w.set(div, "这是div");
console.log(w.get(div)); //"这是div"

div = null;//清除引用对象
console.log(w.get(div)); //undefined

方法

WeakMap实例有get(),set(),has()和delete()方法,用法同Map,也无法被遍历,也无法被清空,所以没有size属性与clear()方法

应用场景

var element=document.getElementById("element");
var w=new WeakMap();
w.set(element,{num:1});
element.onclick=function(){
    var data=w.get(element);
    data.num++;
};
/*
    element为一个DOM节点,每当发生点击事件的时候,就更新内部属性的值,但是确是将新值作为键值放在了        WeakMap中,键名为element,当element这个DOM节点被删除后WeakMap中的值会自动消失,没有了内存泄露的     风险
*/