Map


JavaScript对象本质上是键值对的集合(Hash结构),传统上只能用字符串当做键.为了解决这个问题,ES6提供了Map结构,类似于对象,也是键值对的集合,但键的范围不限于字符串,各种类型的值(包括对象)都能当作键.也就是说,object结构提供了"字符串-值"的对应,Map结构提供了"值-值"的对应,是一种更完美的Hash结构实现

基础使用
  1. 只有同一个对象的引用,Map结构才将其视为同一个键
const map=new Map();
 map.set(['a'],555);
 map.get(['a']) ==>undefined set和get表面针对同一个值,但实际是两个数组,内存地址不一样,因此get方法无法读取该值,返回undefined
  1. 下面列举几个可以识别为同一对象的l例子
let map = new Map();
 map.set(-0, 123);
 map.get(+0) // 123	0和-0是一个值
 map.set(true, 1);
 map.set('true', 2);
 map.get(true) // 1	布尔值true和字符串"true"不是一个值
 map.set(undefined, 3);
 map.set(null, 4);
 map.get(undefined) // 3	 undefined和null也是两个不同的键
 map.set(NaN, 123);
 map.get(NaN) // 123		NaN虽然不严格等于自身,但Map将其视为同一个键
实例的属性和方法
基本属性和方法
  1. size属性 :返回Map结构的成员总数
  2. set(key,value):设置键名key对应的键值为value,然后返回整个Map结构,如果key已经有值,则键值会被更新,否则就会生成新键值.set方法返回的是当前Map对象,因此可以链式编程:let map=new Map().set(1,'a').set(2,'b');
  3. get(key):读取key对应的键值,如果找不到key,返回undefined
  4. has(key):返回一个布尔值,表示某个值是否在当前Map对象之中
  5. delete(key):删除某个键,返回true.如果删除失败,返回false
  6. clear():清除所有成员,没有返回值
遍历方法

Map结构提供三个遍历器生成函数和一个遍历方法,遍历顺序就是插入顺序

  1. keys():返回键名的遍历器
  2. values():返回键值的遍历器
  3. entries():返回所有成员的遍历器.Symbol.iterator属性就是entries方法
  4. forEach():遍历 Map 的所有成员
与其他数据结构相互转换
  1. Map转为数组(使用扩展运算符)
const myMap=new Map()
 	.set(true,7)
 	.set({foo:3},['abc'])	//这里使用了链式编程,Set返回的还是Set结构
 [...myMap]  ==>[[true,7],[{foo:3},['abc']]]	//注意这里的结构,第二个set方法内的整体作为了一个值
  1. 数组转为map(将数组传入Map构造函数)
new Map({
 	[true,7],
 	[{foo: 3}, ['abc']]
 })
 Map{
 	true => 7,
 	Object {foo: 3} => ['abc']
 }
  1. Map转为对象(如果map的键都是字符串,则可以转为对象)
function strMapToObj(strMap) {
 	let obj = Object.create(null);	//通过 Object.create 创建一个空对象
 	for (let [k,v] of strMap) {
 		obj[k] = v;
 	}
 	return obj;
 }
 const myMap = new Map()
 	.set('yes', true)
 	.set('no', false);
 strMapToObj(myMap)
 // { yes: true, no: false }
  1. 对象为Map
function objToStrMap(obj) {
 	let strMap = new Map();
 	for (let k of Object.keys(obj)) {
 		strMap.set(k, obj[k]);
 	}
 	return strMap;
 }
 objToStrMap({yes: true, no: false})
 // Map {"yes" => true, "no" => false}
  1. Map转为JSON(两种情况)
//一种是Map的键名都是字符串,这时可以选择转为对象JSON
 function strMapToJson(strMap) {
 	return JSON.stringify(strMapToObj(strMap));  //strMapToObj是上面第三条的自定义函数
 }
 let myMap = new Map().set('yes', true).set('no', false);
 strMapToJson(myMap)
 // '{"yes":true,"no":false}'
 
 //另一个情况是,Map的键名有非字符串,这时可以选择转为数组JSON
 function mapToArrayJson(map) {
 	return JSON.stringify([...map]);
 }
 let myMap = new Map().set(true, 7).set({foo: 3}, ['abc']);
 mapToArrayJson(myMap)
 // '[[true,7],[{"foo":3},["abc"]]]'
  1. JSON转为Map(正常情况下,所有键名都是字符串)
function jsonToStrMap(jsonStr) {
 	return objToStrMap(JSON.parse(jsonStr));
 }
 jsonToStrMap('{"yes": true, "no": false}')
 // Map {'yes' => true, 'no' => false}
 //有一种特殊情况.整个JSON都是数组,且每个数组成员本身又是有两个成员的数组
 function jsonToMap(jsonStr) {
 	return new Map(JSON.parse(jsonStr));
 }
 jsonToMap('[[true,7],[{"foo":3},["abc"]]]')
 // Map {true => 7, Object {foo: 3} => ['abc']}

WeakMap(与Map结构类似,也是用于生成键值对的集合):

与Map的区别有两点
  1. 只接受对象作为键名(null除外),不接受其他类型的值作为键名
  2. WeakMap的键名指向的对象,不计入垃圾回收机制
设计目的
  • 有时想在某个对象上面存放一些数据,但是会形成对这个对象的引用
  • 举个栗子…
const e1=document.getElementById('foo');
  const e2 = document.getElementById('bar');
  const arr = [
  	[e1, 'foo 元素'],
  	[e2, 'bar 元素'],
  ];
  //上述代码中,e1和e2是两个对象,通过arr数组对其添加一些文字说明,形成了arr对e1和e2的引用,一旦不再需要这两个对象,
  就必须手动删除这个引用,否则垃圾回收机制就不会释放e1和e2占用的内存
  //WeakMap的键名的引用的对象都是弱引用,即垃圾回收机制不将该引用考虑在内.
  //也就是说一旦不再需要,WeakMap里面的键名对象和所对应的键值会自动消失,不用手动删除引用
  • 注意,WeakMap弱引用的只是键名,而不是键值,键值依然正常引用.比如:
const wm=new WeakMap();
  let key={};
  let obj={foo:1};
  wm.set(key,obj);
  obj=null;
  wm.get(key)  ==>Object { foo:1 }
  //上面代码中,键值obj是正常引用,所以,即使在WeakMap外部消除了obj的引用,WeakMap内部的引用依然存在
与Map在API上的区别
  1. 没有遍历操作,也没有size属性
  2. 无法清空,不支持clear方法.因此只有四个方法可用:get(),set(),has(),delete()