WeakMap实现私有属性和防止内存泄露

1. WeakMap 是什么?

WeakMap 与 Map 类似,也是生成 键值对的组合,但是有区别:

只能接受对象作为键名(不包括null);

键名所指向的对象是弱引用,不计入垃圾回收机制;

弱引用是键名,而不是键值,键值依然是正常引用的;

原因:没有办法列出所有键名,某个键名是否存在完成不可预测,这和垃圾回收机制是否允许相关:就算这一刻可以取到键名,下一刻垃圾回收机制突然运行的话这个键名就可能消失,为了防止这种不确定性,所以统一规定不能取到键名)

2. WeakMap防止内存泄露?

dom元素上添加数据时可用 WeakMap,用 WeakMap 好处是当该 DOM 元素被清除,对应的 WeakMap记录就会自动被移除。
例1:

const wm = new WeakMap();
const ele = document.getElementById('example');
wm.set(el, 'some information');
wm.get(el) //"some information"

注册监听事件的listener对象很适合用WeakMap来实现。

例2:

// 代码1
ele.addEventListener('click', handler, false);
 
// 代码2
const listener = new WeakMap();
listener.set(ele, handler);
ele.addEventListener('click', listener.get(ele), false);

代码2比起代码1的好处是:由于监听函数是放在 WeakMap 里面,
则一旦dom对象ele消失,与它绑定的监听函数handler也会自动消失

3. WeakMap 可用来部署类中的私有属性

(ts中已经实现的private私有属性原理就是利用weakmap)

私有属性应该是不能被外界访问到,不能被多个实例共享,js中约定俗成的使用下划线来标记私有属性和方法,一定程度来说是不靠谱的。

下面使用三种方法来实现:闭包(版本1)=》Symbol(版本2)=》WeakMap(版本3)

//简单使用闭包(版本1)
const testFn = (function () {
  let data;

  class Test {
    constructor(val) {
      data = val
    }
    getData() {
      return data;
    }
  }
  return Test;
})();

let test1 = new testFn(3);
let test2 = new testFn(4);
console.log(test1.getData());//4
console.log(test2.getData());//4

可以看到最后都输出4,多实例共享私有属性了,所以版本1不符合。

//使用Symbol(版本2)

const testFn = (function () {
  let data = Symbol('data')

  class Test {
    constructor(val) {
      this[data] = val
    }
    getData() {
      return this[data]
    }
  }
  return Test;
})();

let test1 = new testFn(3);
let test2 = new testFn(4);
console.log(test1.getData());//3
console.log(test2.getData());//4

console.log(test1[Object.getOwnPropertySymbols(test1)[0]]); // 3
console.log(test2[Object.getOwnPropertySymbols(test2)[0]]); // 4

版本2使用symbol来实现,虽然正确输出了3,4,但是我们发现可以在外界不通过getData方法,而是直接拿到私有属性,所以版本2也不符合。

//使用WeakMap(版本3)
const testFn = (function () {
  let data = new WeakMap()

  class Test {
    constructor(val) {
      data.set(this, val)
    }
    getData() {
      return data.get(this)
    }
  }
  return Test;
})();

let test1 = new testFn(3);
let test2 = new testFn(4);
console.log(test1.getData());//3
console.log(test2.getData());//4

如上,完美解决~~

完结撒花,有疑问留言探讨哈~~~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值