Access Modifiers (Private, Protected) in ES6

前端 未结 2 1718
孤城傲影
孤城傲影 2020-12-13 21:59

Note: I already went through the below SO Question and 7 Answers (as of now) about Symbols, WeekMaps and Maps, Please read the full question before you vote:

相关标签:
2条回答
  • 2020-12-13 22:39

    Private properties

    In ES6 (and before), all private property implementations rely on closure.

    People have been doing it even before JavaScript has versions. WeakMap is just a variation that removes the need of new scope and new functions for each new object, at cost of access speed.

    Symbol is a ES6 variation that hides the attribute from common operations, such as simple property access or 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 ] ] );

    As seen above, it can be worked around by Object.getOwnPropertySymbols(). Despite its existence, I always choice symbol over WeakMap. The code is cleaner, simpler, less gc work, and (I think) more efficient.

    I personally avoid class, too. Object.create is much simpler. But that is out of scope.


    Protected properties

    Protected properties, by its nature, requires executing function to know the object of the calling code, to judge whether it should be granted access.

    This is impossible in JS, not because ES6 has no real class, but because caller context is simply unavailable.

    Due to various special natures of JavaScript, for the foreseeable future protected properties shall remain impossible.

    [ Update ] Three years later, thanks to widespread support of module, it is possible to emulate most benefits of protected properties, see the answer below by Twifty. They are still public, but you need to go extra to access them, which means it is difficult to accidentally access or override them. [ /Update ]

    Alternatively...


    Package properties

    Some languages have semi-protected properties, sometimes called "package private", where the method / property is accessible to members in the same module / package.

    ES6 can implement it with closure. It is exactly the same as the private property code above - just share the scope and its symbols with multiple prototypes.

    But this is impractical, since this requires that the whole module be defined under same closed scope, i.e. in a single file. But it is an option nonetheless.

    0 讨论(0)
  • 2020-12-13 22:59

    I'm late to answer this, but it is possible to emulate private AND protected methods in javascript.

    Private methods/properties

    Uses the well known Symbol approach

    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]()
      }
    }
    

    Protected methods/properties

    By their nature, protected members are visible to derived classes. They must also mimic the super.method pattern.

    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]()
      }
    }
    
    0 讨论(0)
提交回复
热议问题