ES6系列Map、WeakMap, Set、WeakSet

195 阅读3分钟

Map和普通对象有什么区别

先来看看Map的定义: Map对象保存键值对,并且能够记住键的原始插入顺序。任何值(对象或者原始值)都可以作为一个键或一个值

  • Map: 的key是有序的,因此,当迭代的时候,一个 Map 对象以插入的顺序返回键值。
  • Object: 一个 Object 的键是无序的
  • Map: 一个 Map的键可以是任意值,包括函数、对象或任意基本类型。
  • Object: Object的键只能是字符串和Symbol 下面是示例
const obj = { id: 1 };
const info = {};
info[obj] = "danceli";
console.log(info)
//结果为: [object Object]: "danceli"
// 为什么会有[object Object] 是因为执行了Object.prototype.toString.call(obj)返回了[object Object]所以对象的键值为这个字符串
//Map

const key1 = {};
const key2 = function() {};
const key3 = []
const map = new Map();

map.set(key1, "1");
map.set(key2, "2");
map.set(key3, "3");
map.set(Symbol("4"), "4");
console.log(map)
// Map的键值可以为任意值

Map的方法

  • Map.prototype.clear() clear()方法会移除Map对象中的所有元素。
  • Map.prototype.delete() delete方法用于移除 Map 对象中指定的元素。map.delete(key)
  • Map.prototype.entries() entries()  方法返回一个新的包含 [key, value] 对的 Iterator 对象,返回的迭代器的迭代顺序与 Map 对象的插入顺序相同。
const map = new Map();
map.set("name", "danceli");
map.set({name: "danceli"}, "12");
const iter = map.entries()
console.log(iter.next()) //{ value: ['name', 'danceli'] }
  • Map.prototype.forEach 会对该方法按照插入顺序进行key,value的遍历
function logMapEle(value, key, map) {
    console.log(`map${key} => ${value}`);
}
new Map([["name", "li"], [NaN, "nan"]]).forEach(logMapEle)
  • Map.prototype.get get() 方法返回某个 Map 对象中的一个指定元素。
  • Map.prototype.has(key) 用来检测是否存在指定元素的键值
  • Map.prototype.keys() keys() 返回一个引用的 Iterator 对象。它包含按照顺序插入 Map 对象中每个元素的key值。
  • Map.prototype.values() values() 返回一个引用的 Iterator 对象。它包含按照顺序插入 Map 对象中每个元素的value值。
  • Map.prototype.set set() 方法为 Map 对象添加或更新一个指定了键(key)和值(value)的(新)键值对。

WeakMap

对象是一组键/值对的集合,其中的键是弱引用的。其键必须是对象,而值可以是任意的。

WeakMap的用处

先看一个例子

const oBtn1 = document.querySelector(".btn1");
const oBtn2 = document.querySelector(".btn2");

function handleBtn1Click() {

}
function handleBtn2Click() {

}
oBtn1.addEventListener("click", handleBtn1Click, false);
oBtn2.addEventListener("click", handleBtn2Click, false);

//如果此时我需要删除这两个按钮元素, 但是他俩绑定了事件处理函数,事件处理函数没有销毁,还存在内存中
oBtn1.remove();
oBtn2.remove();
// 只能通过手动销毁
handleBtn1Click = null;
handleBtn2Click = null;

此时如果我们使用WeakMap就可以更方便

const oBtn1 = document.querySelector(".btn1");
const oBtn2 = document.querySelector(".btn2");

function handleBtn1Click() {

}
function handleBtn2Click() {

}

const map = new WeakMap()
//WeakMap的键名为弱引用,如果别人吧oBtn1或者oBtn2删除了,那么WeakMap里面对应的键名会被回收掉,键名回收掉之后键值也会回收掉
map.set(oBtn1, handleBtn1Click)
map.set(oBtn2 handleBtn2Click)
oBtn1.addEventListener("click", map.get(oBtn1), false);
oBtn2.addEventListener("click",  map.get(oBtn2), false);
oBtn1.remove();
oBtn2.remove();

Set

Set 对象允许你存储任何类型的唯一值,无论是原始值或者是对象引用

// 因为Set中的元素是唯一的所以常用来做数组去重
const arr = [1,2,1,2,3,4,5,7,5,4];
const set = new Set([...arr]);

Set的方法和Map的大概相似,不在多说

WeakSet vs Set的差异

  • WeakSet只能存储对象,而Set可以存储任意数据类型
  • WeakSet存储的对象,如果没有其他的引用的话,这个对象将会被垃圾回收。这就是冠以 Weak 的原因,同时也意味着,WeakSet是不可枚举的,也就没有size。