#Protected State for ECMAScript
Stage NaN Proposal (My Personal Strawman)
##Overview
- Provide
protected
properties & methods for userland object - Only accessible in instance of class defined
protected
properties & methods and that's subclass
##Example
###Single Protected Property
class Foo {
protected bar;
constructor() {
// shorthand for `this##bar = 1;`
##bar = 1;
}
getBar() {
return ##bar;
}
}
class SubFoo extends Foo {
getBarAndIncliment() {
return ##bar++;
}
}
-
This code supported as Syntax Sugar for below ES2015 code (using Class Fields for the sake of clarity):
// utility function createProtectedStorage() { "use strict"; const wm = new WeakMap(); return (self, protectedClass) => { const obj = wm.get(self); if(protectedClass == null) { if(obj) { return obj; } else { const ret = Object.create(null); wm.set(self, ret); return ret; } } const p = new protectedClass(self); if(obj) { for(let key of Reflect.ownKeys(obj)) { const descriptor = Object.getOwnPropertyDescriptor(obj, key); Object.defineProperty(p, key, descriptor); } } wm.set(self, p); return p; } } const _ = createProtectedStorage();
class Protected_Foo { bar; constructor(publicThis) { this.public = publicThis; } } class Foo { constructor() { // protected instance if(new.target === Foo) { _(this, Protected_Foo); } // protected property _(this).bar = 1; } getBar() { return _(this).bar; } } class Protected_SubFoo extends Protected_Foo { } class SubFoo extends Foo { constructor() { super(); // protected instance if(new.target === SubFoo) { _(this, Protected_SubFoo); } } getBarAndIncliment() { return _(this).bar++; } }
###Override Protected Methods
proposal code:
class Foo {
protected bar;
constructor() {
##bar = 1;
}
getBar() {
return ##bar;
}
protected baz() {
++##bar;
}
}
class SubFoo extends Foo {
getBarAndIncliment() {
return ##bar++;
}
protected baz() {
super##baz();
++##bar;
}
callBaz() {
##baz();
}
}
-
in ES2015 (omitted part of the utility code):
class Protected_Foo { bar; constructor(publicThis) { this.public = publicThis; } baz() { ++this.bar; } } class Foo { constructor() { // protected instance if(new.target === Foo) { _(this, Protected_Foo); } // protected property _(this).bar = 1; } getBar() { return _(this).bar; } } class Protected_SubFoo extends Protected_Foo { baz() { super.baz(); ++this.bar; } } class SubFoo extends Foo { constructor() { super(); // protected instance if(new.target === SubFoo) { _(this, Protected_SubFoo); } } getBarAndIncliment() { return _(this).bar++; } callBaz() { _(this).baz(); } }
###Using Public Property in Private Methods
proposal code:
class Name {
name;
constructor(name) {
this.name = name;
}
getDecoratedName(type) {
if(type === "upper") {
return ##upper();
} else if(type === "star") {
return ##star();
} else if(type === "dagger") {
return ##dagger();
}
}
protected upper() {
return this.name.toUpperCase();
}
protected star() {
return `☆${ this.name }☆`;
}
protected dagger() {
return `†${ this.name }†`;
}
}
-
in ES2015 (omitted part of the utility code):
class Protected_Name { constructor(publicThis) { this.public = publicThis; } upper() { return this.public.name.toUpperCase(); } star() { return `☆${ this.public.name }☆`; } dagger() { return `†${ this.public.name }†`; } } class Name { name; constructor(name) { // protected instance if(new.target === Name) { _(this, Protected_Name); } // public property this.name = name; } getDecoratedName(type) { if(type === "upper") { return _(this).upper(); } else if(type === "star") { return _(this).star(); } else if(type === "dagger") { return _(this).dagger(); } } }
##Private/Protected Library by Other Thoughts
access-modifiers (npm module): based on Symbol, non-strict private/protected state but reflectable
##Related Proposals in ES.next
- Class Property Declarations (Stage 1)
- Private State for objects, Private Fields (Stage 0)