"private property" 在 ES6 类 上意味着什么?

What "private property" means on ES6 classes?

我对 Classes 上的 ES6 隐私有点迷茫。我有这个 Class:

class Whatever {

        constructor(value) {
            this._value = Number(value);
        }

        total() {
            return this._value * 2;
        }
    }

    let instance = new Whatever('1000');
    console.log(instance.total() );     // 2000     
    console.log(instance._value  );     // 1000

我正在尝试了解 Symbol() 如何工作以保持数据的私密性 (see link),并且在阅读文档后,我正在尝试对此做一个简单的示例,但似乎没有任何差异:

const _value = Symbol('value');

    class Whatever {

        constructor(value) {
            this[_value] = Number(value);
        }

        total() {
            return this[_value] * 2;
        }
    }


    let instance = new Whatever('1000');
    console.log(instance.total() );     // 2000     
    console.log(instance[_value]  );    // 1000

有人可以全面地向我解释一下,隐私在这种情况下意味着什么,以及为什么我将数据私有化(使数据无法从 Class 外部访问)的想法是错误的?我对 OOP 的经验不多。

谢谢。

这里有一些微妙的概念。

Symbols 是全局唯一的;也就是说,如果你两次调用Symbol.create('somestring');,它会产生两个完全不同的符号。

如果不通过其他方式访问该符号,"someone else" 无法访问键为符号** 的对象 属性。在您的第二个示例中, class 下方的代码仍然具有对该符号的词法访问权限。然而,如果你的 class 被导出,无论是通过模块系统还是只是返回到一些没有词法访问的其他调用函数,情况就不会是这样,即使他们知道你用来标记符号的字符串,因为他们无法重新创建它(如上所述)。

** 编辑 2:正如其他人所说,包括 Rauschmayer 博士,"others" 可以通过 Reflect.ownKeys(object) 访问键,包括符号。在这种非常慎重的情况下,人们会希望对方知道他们在做什么……所以使用符号作为键的整个范例仍然有助于确保键的非冲突命名空间(例如,如果其他人想要在不意外覆盖其任何重要 "internal" 属性的情况下扩充您的对象)。但是,它不足以 100% 防止故意访问或修改。 (作品中有一个相关的ECMAScript proposal,有趣的阅读。)

编辑:这是一个例子

let Whatever = (function() {
      const _value = Symbol('value');

      class Whatever {

        constructor(value) {
          this[_value] = Number(value);
        }

        total() {
          return this[_value] * 2;
        }
      }
      
      return Whatever;
    })(); // IIFE


    let instance = new Whatever('1000');
    console.log(instance.total()); // 2000     
    console.log(instance._value); // undefined
    console.log(instance[_value]); // ReferenceError: _value is not defined

假设您不遍历 class.

的可枚举属性,您的示例没有真正的区别

考虑以下几点:

function MyFunction () {
  const _private = new Symbol();

  this[_private] = 5;
  this.public = 10;
}

const thing = new MyFunction();

for (let key in thing) { // prints 10
  console.log(thing[key]);
}

console.log(thing.public); // prints 10
console.log(thing._private); // undefined

由符号命名的属性是不可枚举的,因此在某种意义上它们不是 "exposed"。符号的另一个好处是它们保证创建唯一的键,所以不用担心键名冲突。

为了简单起见,我选择用函数而不是 class 来说明它。对于 class 您可以执行以下操作(这都是关于 "protecting" 符号的范围):

const MyClass = (function () {
  const _value = Symbol();
  return class _MyClass {
    constructor() {
      this[_value] = 5;
    }
  }
})();

免责声明:这不是 "true" 隐私,因为仍然有办法枚举符号。我认为最大的优势是名称冲突。