【问题标题】:What "private property" means on ES6 classes?ES6 类中的“私有财产”是什么意思?
【发布时间】:2017-06-05 23:22:48
【问题描述】:

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

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

有人可以全面解释一下,隐私在这个案例中是什么意思,为什么我将数据私有化(使数据无法从班级外部访问)的想法是错误的?我在 OOP 方面没有太多经验。

谢谢。

【问题讨论】:

  • 它是一样的,正如链接文章提到的那样:它们(两者)“对外界有些隐藏,但并不完全”。

标签: javascript oop private


【解决方案1】:

假设您不循环遍历类的可枚举属性,则您的示例没有真正的区别。

考虑以下几点:

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

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

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

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

免责声明:这不是“真正的”隐私,因为仍有枚举符号的方法。我认为最大的优势是名称冲突。

【讨论】:

    【解决方案2】:

    这里有一些微妙的概念。

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

    如果不以其他方式访问该符号,“其他人”就无法访问其键是符号**的对象属性。在您的第二个示例中,类下的代码仍然可以对符号进行词法访问。但是,如果要导出您的类,无论是通过模块系统还是仅返回到没有词法访问的其他调用函数,即使他们知道您用来标记符号的字符串,情况也不会如此,因为他们不能重新创建它(如上所述)。

    ** 编辑 2:正如其他人所说,包括 Rauschmayer 博士,“其他人”可以通过 Reflect.ownKeys(object) 访问密钥,包括符号。在这种经过深思熟虑的情况下,人们希望对方知道他们在做什么......所以使用符号作为键的整个范例仍然有利于确保键的非冲突命名空间(例如,如果其他人想要增强您的对象,而不会意外覆盖其任何重要的“内部”属性)。但是,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

    【讨论】:

    • @le_m 啊,你是对的。因此,这将是另一方故意反思的情况,而不仅仅是试图防止名称冲突。谢谢你的指出,我会更新我的答案。
    • 非常感谢,谢谢。我已经标记了另一个答案,因为两者都是有效的,但最旧的答案是另一个。
    猜你喜欢
    • 2011-04-29
    • 2017-06-11
    • 2019-12-05
    • 2013-04-27
    • 2018-05-18
    • 2012-10-11
    • 2023-03-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多