16. Map
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中的值会自动消失,没有了内存泄露的 风险
*/