在 Javascript 原型中,有什么方法既可以利用信息隐藏又不会浪费内存?

Is there any way to make use of information hiding while not wasting memory in Javascript prototypes?

我正在关注 Crockford's guide to private methods in Javascript,但我遇到了一些困难。我正在尝试优化此代码

function Container(param) {

    function dec() {
        if (secret > 0) {
            secret -= 1;
            return true;
        } else {
            return false;
        }
    }

    this.member = param;
    var secret = 3;
    var that = this;

    this.service = function () {
        return dec() ? that.member : null;
    };
}

通过在构造函数之外定义函数,这样每次创建新实例时都不会创建新的函数对象。

我仍然不知道如何为他称为私有方法的方法执行此操作(非常感谢任何帮助)。对于那些他称之为特权方法的人,这就是我正在尝试做的事情:

function Container(param) {

    function dec() {
        if (secret > 0) {
            secret -= 1;
            return true;
        } else {
            return false;
        }
    }

    this.member = param;
    var secret = 3;
    var that = this;
}
Container.prototype.service = function() {
    return dec() ? that.member : null; 
};

但如果我这样测试它

d1 = new Container("content");
d1.service();

我收到这个错误:

ReferenceError: dec is not defined

这是否意味着无法利用 Crockford 使用的 private/privileged 方法的优势,并通过将 class 的所有实例链接到同一个函数对象来优化内存使用?我希望你能证明我错了。

如果你不想在每次调用 Container 时创建一个新的 dec,你可以将 Container 变成一个 IIFE - 定义 decContainer 被定义,然后 return 来自 IIFE 的实际 Container 构造函数,因此 dec 只能从 Container 内部引用。要封装 secrets,请使用由实例索引的 Map 而不是在构造函数中使用普通的 var secrets,以便(共享)decservice函数可以查看和使用地图。

实际上,如评论所述,使用 Wea​​kMap 可能更好,这样一旦实例被 GC 处理,实例的关联秘密就可以被垃圾回收:

const Container = (() => {
  const secretsByInstance = new WeakMap();
  function dec(instance) {
    const secret = secretsByInstance.get(instance);
    if (secret > 0) {
      secretsByInstance.set(instance, secret - 1);
      return true;
    } else {
      return false;
    }
  }
  function Container(param) {
    secretsByInstance.set(this, 3);
    this.member = param;
  }
  Container.prototype.service = function() {
   return dec(this) ? this.member : null;
  };
  return Container;
})();

d1 = new Container("content");
console.log(d1.service());
console.log(d1.service());
console.log(d1.service());
console.log(d1.service());