是否可以在 ES6 类中创建私有属性?
这是一个例子。我怎样才能阻止访问instance.property
?
class Something {
constructor(){
this.property = "test";
}
}
var instance = new Something();
console.log(instance.property); //=> "test"
是否可以在 ES6 类中创建私有属性?
这是一个例子。我怎样才能阻止访问instance.property
?
class Something {
constructor(){
this.property = "test";
}
}
var instance = new Something();
console.log(instance.property); //=> "test"
简短的回答,不,ES6 类没有对私有属性的本机支持。
但是您可以通过不将新属性附加到对象,而是将它们保存在类构造函数中来模拟这种行为,并使用 getter 和 setter 来访问隐藏的属性。请注意,getter 和 setter 会在类的每个新实例上重新定义。
ES6
class Person {
constructor(name) {
var _name = name
this.setName = function(name) { _name = name; }
this.getName = function() { return _name; }
}
}
ES5
function Person(name) {
var _name = name
this.setName = function(name) { _name = name; }
this.getName = function() { return _name; }
}
私有类功能处于第 3 阶段提案中。所有主要浏览器都支持其大部分功能。
class Something {
#property;
constructor(){
this.#property = "test";
}
#privateMethod() {
return 'hello world';
}
getPrivateMessage() {
return this.#property;
}
}
const instance = new Something();
console.log(instance.property); //=> undefined
console.log(instance.privateMethod); //=> undefined
console.log(instance.getPrivateMessage()); //=> test
console.log(instance.#property); //=> Syntax error
扩展@loganfsmyth 的回答:
JavaScript 中唯一真正私有的数据仍然是作用域变量。在内部访问属性的意义上,您不能拥有与公共属性相同的属性的私有属性,但您可以使用作用域变量来存储私有数据。
这里的方法是使用私有的构造函数的作用域来存储私有数据。对于可以访问这些私有数据的方法,它们也必须在构造函数中创建,这意味着您要在每个实例中重新创建它们。这是性能和内存损失,但有些人认为这种损失是可以接受的。对于不需要访问私有数据的方法,可以通过像往常一样将它们添加到原型中来避免惩罚。
例子:
function Person(name) {
let age = 20; // this is private
this.name = name; // this is public
this.greet = function () {
// here we can access both name and age
console.log(`name: ${this.name}, age: ${age}`);
};
}
let joe = new Person('Joe');
joe.greet();
// here we can access name but not age
WeakMap 可用于避免先前方法的性能和内存损失。WeakMaps 将数据与对象(这里是实例)相关联,以便只能使用该 WeakMap 访问它。因此,我们使用作用域变量方法创建私有 WeakMap,然后使用该 WeakMap 检索与 关联的私有数据this
。这比作用域变量方法更快,因为您的所有实例都可以共享一个 WeakMap,因此您无需重新创建方法只是为了让它们访问自己的 WeakMap。
例子:
let Person = (function () {
let privateProps = new WeakMap();
class Person {
constructor(name) {
this.name = name; // this is public
privateProps.set(this, {age: 20}); // this is private
}
greet() {
// Here we can access both name and age
console.log(`name: ${this.name}, age: ${privateProps.get(this).age}`);
}
}
return Person;
})();
let joe = new Person('Joe');
joe.greet();
// here we can access joe's name but not age
本示例使用一个 Object 将一个 WeakMap 用于多个私有属性;您还可以使用多个 WeakMap 并age.set(this, 20)
像privateProps.set(this, 'age', 0)
.
这种方法的隐私理论上可以通过篡改全局WeakMap
对象而被破坏。也就是说,所有 JavaScript 都可以被损坏的全局变量破坏。我们的代码已经建立在这种情况不会发生的假设之上。
(此方法也可以使用Map
,但WeakMap
更好,因为Map
除非您非常小心,否则会造成内存泄漏,为此,两者没有其他区别。)
Symbol 是一种可以用作属性名称的原始值。您可以使用作用域变量方法创建一个私有 Symbol,然后将私有数据存储在this[mySymbol]
.
这种方法的隐私可以使用 被破坏Object.getOwnPropertySymbols
,但做起来有些尴尬。
例子:
let Person = (function () {
let ageKey = Symbol();
class Person {
constructor(name) {
this.name = name; // this is public
this[ageKey] = 20; // this is intended to be private
}
greet() {
// Here we can access both name and age
console.log(`name: ${this.name}, age: ${this[ageKey]}`);
}
}
return Person;
})();
let joe = new Person('Joe');
joe.greet();
// Here we can access joe's name and, with a little effort, age. ageKey is
// not in scope, but we can obtain it by listing all Symbol properties on
// joe with `Object.getOwnPropertySymbols(joe)`.
旧的默认值,只使用带有下划线前缀的公共属性。虽然在任何方面都不是私有财产,但这种约定非常普遍,它很好地传达了读者应该将财产视为私有财产,这通常可以完成工作。作为这种失误的交换,我们得到了一种更容易阅读、更容易打字和更快的方法。
例子:
class Person {
constructor(name) {
this.name = name; // this is public
this._age = 20; // this is intended to be private
}
greet() {
// Here we can access both name and age
console.log(`name: ${this.name}, age: ${this._age}`);
}
}
let joe = new Person('Joe');
joe.greet();
// Here we can access both joe's name and age. But we know we aren't
// supposed to access his age, which just might stop us.
截至 ES2017,仍然没有完美的方法来处理私有属性。各种方法各有利弊。作用域变量是真正私有的;作用域 WeakMap 非常私有,比作用域变量更实用;作用域符号是相当私密且相当实用的;下划线通常足够私密且非常实用。
是的,有 - 用于对象中的范围访问 - ES6 引入了Symbol
s。
符号是独一无二的,除了反射(如 Java/C# 中的私有)之外,您无法从外部访问一个符号,但任何有权访问内部符号的人都可以使用它进行密钥访问:
var property = Symbol();
class Something {
constructor(){
this[property] = "test";
}
}
var instance = new Something();
console.log(instance.property); //=> undefined, can only access with access to the Symbol
答案是不”。但是您可以像这样创建对属性的私有访问:
export
关键字将其公开。(在 ES6 规范的早期版本中,可以使用 Symbols 来确保隐私的建议是正确的,但现在不再如此:https : //mail.mozilla.org/pipermail/es-discuss/2014-January/035604。 html和https://stackoverflow.com/a/22280202/1282216。有关符号和隐私的更详细讨论,请参阅:https : //curiosity-driven.org/private-properties-in-javascript )