ES6中的访问修饰符(专用,受保护)

时间:2015-12-29 19:17:31

标签: ecmascript-6 access-modifiers

  

注意:我已经完成了关于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
  

我希望这个属性和方法在它自己的类和扩展它的类中可见。

实现此行为的解决方法/更好的解决方案

2 个答案:

答案 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工作,并且(我认为)更有效。

  

我个人也避免classObject.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]()
  }
}