是否可以在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引入了符号。
符号是唯一的,你不能从外部访问一个,除非通过反射(就像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
大多数答案要么说不可能,要么要求你使用WeakMap或Symbol,这是ES6的特性,可能需要腻子。然而,还有另一种方法!看看这个:
// 1. Create closure var SomeClass = function() { // 2. Create `key` inside a closure var key = {}; // Function to create private storage var private = function() { var obj = {}; // return Function to access private storage using `key` return function(testkey) { if(key === testkey) return obj; // If `key` is wrong, then storage cannot be accessed console.error('Cannot access private properties'); return undefined; }; }; var SomeClass = function() { // 3. Create private storage this._ = private(); // 4. Access private storage using the `key` this._(key).priv_prop = 200; }; SomeClass.prototype.test = function() { console.log(this._(key).priv_prop); // Using property from prototype }; return SomeClass; }(); // Can access private property from within prototype var instance = new SomeClass(); instance.test(); // `200` logged // Cannot access private property from outside of the closure var wrong_key = {}; instance._(wrong_key); // undefined; error logged
我称这个方法为accessor pattern。基本思想是我们有一个闭包,闭包中有一个键,我们创建一个私有对象(在构造函数中),只有当你拥有键时才能访问它。
如果你感兴趣,你可以在我的文章中阅读更多有关这方面的内容。使用此方法,可以为每个对象创建不能在闭包外部访问的属性。因此,你可以在构造函数或原型中使用它们,但不能在其他任何地方使用。我还没有在任何地方见过这种方法,但我认为它真的很强大。
甚至Typescript也做不到。从他们的文档来看:
当成员被标记为private时,就不能从其包含类的外部访问它。例如: 动物类{ 私有名称:字符串; 构造函数(名称:字符串){this.name =名称;} } 新的动物(猫). name;//错误:'name'是private;
但在他们的操场上,这说明:
var Animal = (function () {
function Animal(theName) {
this.name = theName;
}
return Animal;
}());
console.log(new Animal("Cat").name);
所以他们的“私人”关键字是无效的。
这段代码演示了私有和公共、静态和非静态、实例级和类级、变量、方法和属性。
https://codesandbox.io/s/class-demo-837bj
class Animal { static count = 0 // class static public static #ClassPriVar = 3 // class static private constructor(kind) { this.kind = kind // instance public property Animal.count++ let InstancePriVar = 'InstancePriVar: ' + kind // instance private constructor-var log(InstancePriVar) Animal.#ClassPriVar += 3 this.adhoc = 'adhoc' // instance public property w/out constructor- parameter } #PawCount = 4 // instance private var set Paws(newPawCount) { // instance public prop this.#PawCount = newPawCount } get Paws() { // instance public prop return this.#PawCount } get GetPriVar() { // instance public prop return Animal.#ClassPriVar } static get GetPriVarStat() { // class public prop return Animal.#ClassPriVar } PrintKind() { // instance public method log('kind: ' + this.kind) } ReturnKind() { // instance public function return this.kind } /* May be unsupported get #PrivMeth(){ // instance private prop return Animal.#ClassPriVar + ' Private Method' } static get #PrivMeth(){ // class private prop return Animal.#ClassPriVar + ' Private Method' } */ } function log(str) { console.log(str) } // TESTING log(Animal.count) // static, avail w/out instance log(Animal.GetPriVarStat) // static, avail w/out instance let A = new Animal('Cat') log(Animal.count + ': ' + A.kind) log(A.GetPriVar) A.PrintKind() A.Paws = 6 log('Paws: ' + A.Paws) log('ReturnKind: ' + A.ReturnKind()) log(A.adhoc) let B = new Animal('Dog') log(Animal.count + ': ' + B.kind) log(B.GetPriVar) log(A.GetPriVar) // returns same as B.GetPriVar. Acts like a class-level property, but called like an instance-level property. It's cuz non-stat fx requires instance. log('class: ' + Animal.GetPriVarStat) // undefined log('instance: ' + B.GetPriVarStat) // static class fx log(Animal.GetPriVar) // non-stat instance fx log(A.InstancePriVar) // private log(Animal.InstancePriVar) // private instance var log('PawCount: ' + A.PawCount) // private. Use getter /* log('PawCount: ' + A.#PawCount) // private. Use getter log('PawCount: ' + Animal.#PawCount) // Instance and private. Use getter */
我意识到这里有很多答案。我想分享我的解决方案,它确保了ES6类和旧JS中真正的私有变量。
var MyClass = (function() {
var $ = new WeakMap();
function priv(self) {
var r = $.get(self);
if (!r) $.set(self, r={});
return r;
}
return class { /* use priv(this).prop inside your class */ }
}();
外部世界无法访问$,这一事实确保了隐私。
当实例消失时,WeakMap将释放数据。
这肯定在纯Javascript中工作,我相信他们在ES6类中工作,但我还没有测试$将在成员方法的范围内可用。