WeakMap 与 Symbol 在类私有数据的应用

用 WeakMap 实现

let _counter = new WeakMap();
let _action = new WeakMap();

class Countdown {
  constructor(counter, action) {
    _counter.set(this, counter);
    _action.set(this, action);
  }
  dec() {
    let counter = _counter.get(this);
    if (counter < 1) return;
    counter--;
    _counter.set(this, counter);
    if (counter === 0) {
      _action.get(this)();
    }
  }
}

WeakMap 的键名是对象的弱引用,其所对应的对象可能会被自动回收,只要不暴露 WeakMap,私有数据就是安全的。

Pros.

  • 私有属性命名不会冲突

Cons.

  • 代码不够优雅

用 Symbol 实现

const _counter = Symbol('counter');
const _action = Symbol('action');

class Countdown {
  constructor(counter, action) {
    this[_counter] = counter;
    this[_action] = action;
  }
  dec() {
    if (this[_counter] < 1) return;
    this[_counter]--;
    if (this[_counter] === 0) {
      this[_action]();
    }
  }
}

每一个 Symbol 都是唯一的,这就是为什么使用 Symbol 的属性键名之间不会冲突的原因。并且,Symbol 某种程度上来说是隐式的,但也并不完全是:

let c = new Countdown(2, () => console.log('DONE'));

console.log(Object.keys(c));
// []
console.log(Reflect.ownKeys(c));
// [Symbol(counter), Symbol(action)]

Pros.

  • 私有属性命名不会冲突

Cons.

  • 代码不够优雅
  • 不太安全,可以通过 Reflect.ownKeys() 列表一个对象所以的属性键名