如何实现构造函数中`this`中保存的值的隐私?

Joh*_*ton 12 javascript

对于需要保存在this构造函数中的值,我有哪些选择可以实现隐私?例如一个简单的Stack实现:

function Stack(){
  this._stack = {}
  this._counter = 0
}

Stack.prototype.push = function (item){
  this._stack[this._counter++] = item
  return this
}

Stack.prototype.pop = function (){
  Reflect.deleteProperty(this._stack, --this._counter);
  return this
}

Stack.prototype.peek = function (){
  return this._stack[this._counter - 1]
}

Stack.prototype.length = function (){
  return Object.values(this._stack).length
}

Run Code Online (Sandbox Code Playgroud)

如果这些方法没有定义为原型方法,我可以像这样轻松地私有它们:

function Stack(){
  let _stack = {}
  let _counter = 0

  this.push = function (item){
    _stack[_counter++] = item
    return this
  }

  this.pop = function (){
    Reflect.deleteProperty(_stack, --_counter);
    return this
  }

  this.peek = function (){
    return _stack[_counter - 1]
  }

  this.length = function (){
    return Object.values(_stack).length
  }
}

Run Code Online (Sandbox Code Playgroud)

这种方式_stack_counter没有暴露出来,但是这些方法不在原型链上。

是否有可能实现隐私,而受保护的值保存在this

qui*_*cVO 9

这是使用私有字段的示例。您可以使用static关键字将它们设为静态,但这在本示例中不是必需的。

class test {
    #lol = 29;
    #mas = 15;
    constructor() {
        this.#lol++;
        this.#mas--;
        return {
            value: this.#lol - this.#mas
        };
    }
};
console.log(new test().value); // --> 16
Run Code Online (Sandbox Code Playgroud)


3li*_*t0r 5

MDN 在其Keyed 集合指南中提供了私有属性的示例。

弱映射对象

对象WeakMap是键/值对的集合,其中键只是对象,值可以是任意值。键中的对象引用被保留,这意味着如果不再有其他对该对象的引用,它们将成为垃圾收集 (GC) 的目标。APIWeakMap与API相同Map

与对象的一个​​区别MapWeakMap键不可枚举(即,没有方法为您提供键列表)。如果是的话,列表将取决于垃圾收集的状态,从而引入非确定性。

有关更多信息和示例代码,另请参阅“为什么是弱映射?” 在参考页上WeakMap

对象的一种用例WeakMap是存储对象的私有数据,或隐藏实现细节。以下示例来自 Nick Fitzgerald 的博客文章“使用 ECMAScript 6 WeakMaps 隐藏实现细节”。私有数据和方法属于对象内部并存储在对象中。实例和原型上暴露的所有内容都是公开的;其他一切都无法从外部世界访问,因为没有从模块导出。privates WeakMapprivates

const privates = new WeakMap();

function Public() {
  const me = {
    // Private data goes here
  };
  privates.set(this, me);
}

Public.prototype.method = function () {
  const me = privates.get(this);
  // Do stuff with private data in `me`...
};

module.exports = Public;
Run Code Online (Sandbox Code Playgroud)

应用于您的场景,这可能如下所示:

const Stack = (function () {
  const privates = new WeakMap();

  function Stack() {
    privates.set(this, { stack: {}, counter: 0 });
  }

  Stack.prototype.push = function (item) {
    const _ = privates.get(this);
    _.stack[_.counter++] = item;
    return this;
  };

  Stack.prototype.pop = function () {
    const _ = privates.get(this);
    Reflect.deleteProperty(_.stack, --_.counter);
    return this;
  };

  Stack.prototype.peek = function () {
    const _ = privates.get(this);
    return _.stack[_.counter - 1];
  };

  Stack.prototype.length = function () {
    const _ = privates.get(this);
    return Object.values(_.stack).length;
  };
  
  return Stack;
})();
Run Code Online (Sandbox Code Playgroud)