注意:我已经完成了关于Symbols,WeekMaps和地图的以下SO问题和7个答案(截至目前),请在投票前阅读完整的问题:Private properties in JavaScript ES6 classes
文章:https://esdiscuss.org/topic/es7-property-initializers
以下是我的Simple Class
,其中包含私有,公共和受保护的属性和方法。
'use strict';
class MyClass {
constructor () {
this.publicVar = 'This is Public Variable';
this.privateVar = 'This is Private Variable';
this.protectedVar = 'This is Protected Variable';
} // Public Constructor Method.
publicMethod () {
console.log(' Accessing this.publicVar: ', this.publicVar);
console.log(' Accessing this.privateVar: ', this.privateVar);
console.log(' Accessing this.protectedVar: ', this.protectedVar);
return 'Its Public Method'
} // Public Method.
privateMethod () {return 'Its Private Method'} // Private Method.
protectedMethod () {return 'Its Protected Method'} // Protected Method.
foo () {
this.publicMethod();
this.privateMethod();
this.protectedMethod();
} // Public Method
} // end class
我正在实例化Object并调用正常工作的公共方法。
let MyObject = new MyClass;
MyObject.foo(); // Works fine.
console.log( MyObject.publicVar ); // Works
console.log( MyObject.publicMethod() ); // Works
按预期工作。
现在我的问题。我知道在ES6规范中很少有像Symbol这样的东西,获得受保护的当前变通方法以及在ES6类上工作的私有变量/方法。
console.log( MyObject.privateVar ); // Works
console.log( MyObject.privateMethod() ); // Works
我希望这个属性和方法只在它自己的类中可见。
console.log( MyObject.protectedVar ); // Works
console.log( MyObject.protectedMethod() ); // Works
我希望这个属性和方法在它自己的类和扩展它的类中可见。
实现此行为的解决方法/更好的解决方案
答案 0 :(得分:9)
私有资产
在ES6(以及之前)中,所有私有属性实现都依赖于closure。
人们have been doing it甚至在JavaScript版本之前。 WeakMap只是一种变体,它以访问速度为代价,消除了对每个新对象的新范围和新功能的需求。
符号是一种ES6变体,它隐藏了常见操作的属性,例如简单的属性访问或for in
。
var MyClass;
( () => {
// Define a scoped symbol for private property A.
const PropA = Symbol( 'A' );
// Define the class once we have all symbols
MyClass = class {
someFunction () {
return "I can read " + this[ PropA ]; // Access private property
}
}
MyClass.prototype[ PropA ] = 'Private property or method';
})();
// function in the closure can access the private property.
var myObject = new MyClass();
alert( myObject.someFunction() );
// But we cannot "recreate" the Symbol externally.
alert( myObject[ Symbol( 'A' ) ] ); // undefined
// However if someone *really* must access it...
var symbols = Object.getOwnPropertySymbols( myObject.__proto__ );
alert( myObject[ symbols[ 0 ] ] );
如上所述,它可以由Object.getOwnPropertySymbols()解决。 尽管存在,我总是在WeakMap上选择符号。 代码更清晰,更简单,更少gc工作,并且(我认为)更有效。
我个人也避免
class
。Object.create
要简单得多。但这超出了范围。
受保护的属性
受保护的属性本质上需要执行函数来知道调用代码的对象,以判断是否应授予其访问权。
这在JS中是不可能的,不是因为ES6有no real class,而是因为来电者上下文是simply unavailable。
由于JavaScript的various special natures,在可预见的将来,受保护的属性仍然无法使用。
...替代地
套餐属性
某些语言具有半保护属性,有时称为“包私有”,其中方法/属性可供同一模块/包中的成员访问。
ES6可以通过关闭来实现它。 它与上面的私有属性代码完全相同 - 只是用多个原型共享范围及其符号。
但这是不切实际的,因为这要求整个模块在相同的封闭范围内定义,即在单个文件中。 但它仍然是一种选择。
答案 1 :(得分:1)
我迟到了,但是可以在javascript中模拟私有和受保护的方法。
私有方法/属性
使用众所周知的符号方法
const someMethod = Symbol()
const someProperty = Symbol()
export default class Parent {
constructor () {
this[someProperty] = 'and a private property'
}
[someMethod] () {
console.log('this is a private method')
console.log(this[someProperty])
}
callPrivateMethod () {
this[someMethod]()
}
}
受保护的方法/属性
就其性质而言,受保护的成员对派生类是可见的。他们还必须模仿super.method
模式。
symbols.js
export default {
protectedMethod: Symbol()
}
parent.js
import symbols from './symbols'
const someMethod = Symbol()
const someProperty = Symbol()
export default class Parent {
constructor () {
this[someProperty] = 'and a private property'
}
[someMethod] () {
console.log('this is a private method')
console.log(this[someProperty])
}
[symbols.protectedMethod] () {
console.log('I am the parent')
}
callPrivateMethod () {
this[someMethod]()
}
}
child.js
import Parent from './parent'
import symbols from './symbols'
export default class Child {
[symbols.protectedMethod] () {
console.log('I am the child')
super[symbols.protectedMethod]()
}
callProtectedMethod () {
this[symbols.protectedMethod]()
}
}