Map 和 WeakMap 详解

91 阅读2分钟

1. 为什么会出现 Map?

结论:弥补对象的 key 只能是字符串,不能是对象的缺陷。

例子如下:

// Object 的对象只能是字符串,所以下面的 kk 中的 k,y 实际上被转化成字符串。
const k = {name:1};
const y = "age"
const kk = {
  k:'pang',
  y:18
}
console.log(kk)

输出结果如下:

// 如果想用变量作为 key 需要用下面这种写法,用[] 包裹
const k = {name:1};
const y = "age"
const kk = {
  [k]:'pang',
  [y]:18
}
console.log(kk)

输出如下:

重点⚠️:

可以看到,因为 Object 的对象只能是 string 类型,所以会自动地把变量的内容通过 Object.prototype.toString.call(值) 转换成 字符串。所以如果变量是个引用类型,就是被转换成 [object Object]

所以下面这段代码:

// 如果有多个引用类型
const k = {name:1};
const z = {hobby:'coding'}
const y = "age"
const kk = {
  [k]:'pang',
  [z]:'dddd',
  [y]:18
}
console.log(kk)

输出结果是:

2. Map

也具有不重复性,不过有些特殊,对于 -0,+0 和 NaN 的处理不太一样

// 认为 -0 等于 0 ; NaN 等于 NaN
const map = new Map();
map.set(0,'1');
map.set(-0,'2');
map.set(NaN,'3');
map.set(NaN,'4');
console.log(map)

方法如下:

初始化Map:

应该是传入二维数组 [[],[]] 。

const map = new Map([["a",'1'],["b",2]]);
console.log(map)

赋值:

const map = new Map();
map.set(key,value)

一个容易被误导的问题:

const map = new Map();
map.set(['a'],1);
map.set(['a'],2);
console.log(map.get(['a']))


//结果是 undefined ,因为这三个引用类型都是独立的数据哦,别因为一样被误解,避免这种可以用变量

const a = ['a']
const map = new Map();
map.set(a,1);
map.set(a,2);
console.log(map.get(a))   // 2 

3. WeakMap

弱集合中的键 只能是 Object 或者继承自 Object 的类型。

主要作用:弱引用(针对内存泄露的问题)和 私有成员

使用场景:

  1. 使资源被垃圾回收机制及时回收

例如有一个 add 按钮,控制 count = 0,点击 count + 1。当使用完的时候,要移除点击事件,但是如果不移除 count ,它就会一直存在,如果这个按钮控制更多数据,那就会有更多数据保存在内存中没有被释放。这个时候如果使用弱引用 WeakMap 保存,以按钮作为key ,控制的数据为值,当移除按钮的时候其值也会被回收,避免的占用内存的问题。

let wm = new WeakMap(); 
wm.set(button,{count:0})
  1. 私有成员
const User = (() => { 
  const wm = new WeakMap(); 
  class User { 
    constructor(id) { 
      this.idProperty = Symbol('id'); 
      this.setId(id); 
    } 
    setPrivate(property, value) { 
      const privateMembers = wm.get(this) || {}; 
      privateMembers[property] = value; 
      wm.set(this, privateMembers); 
    } 
    getPrivate(property) { 
      return wm.get(this)[property]; 
    } 
    setId(id) { 
      this.setPrivate(this.idProperty, id); 
    } 
    getId(id) { 
      return this.getPrivate(this.idProperty); 
    } 
  } 
  return User; 
})();

const user = new User(123); 
alert(user.getId()); // 123 
user.setId(456); 
alert(user.getId()); // 456