web-dev-qa-db-ja.com

ES6のアクセス修飾子(プライベート、保護)

注:私はすでに以下のSO質問と7つの回答(現時点))について シンボル 、WeekMapsとマップを確認しました。投票する前に質問全体をお読みください。 JavaScript ES6クラスのプライベートプロパティ
記事: 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

オブジェクトをインスタンス化し、期待どおりに機能しているパブリックメソッドを呼び出しています。

let MyObject = new MyClass;
MyObject.foo(); // Works fine.
console.log( MyObject.publicVar ); // Works
console.log( MyObject.publicMethod() ); // Works

期待どおりに機能しています。

今私の質問。私はSymbolのようないくつかのものがES6仕様にあることを知っています、保護されたプライベート変数/メソッドをES6クラスで動作させるための現在の回避策は何ですか。

console.log( MyObject.privateVar ); // Works
console.log( MyObject.privateMethod() ); // Works

このプロパティとメソッドをそれ自体のクラスでのみ表示したいと思います。

console.log( MyObject.protectedVar ); // Works
console.log( MyObject.protectedMethod() ); // Works

このプロパティとメソッドを、それ自体のクラスとそれを拡張するクラス内で表示できるようにします。

この動作を実現するための回避策/より良い解決策をいただければ幸いです

8
Alamelu Venkat

プライベートプロパティ

ES6(およびそれ以前)では、すべての私有財産の実装は クロージャ に依存しています。

人々 それをやっている JavaScriptにバージョンがある前でさえ。 WeakMapは、アクセス速度を犠牲にして、新しいオブジェクトごとに新しいスコープと新しい関数の必要性を排除する単なるバリエーションです。

Symbolは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に 実際のクラスがない があるためではなく、呼び出し元context単に使用できない であるためです。

JavaScriptの variousspecialnatures のため、当面の間、保護されたプロパティは不可能なままです。

あるいは...


パッケージプロパティ

一部の言語には、「パッケージプライベート」と呼ばれることもある半保護されたプロパティがあり、同じモジュール/パッケージのメンバーがメソッド/プロパティにアクセスできます。

ES6はクロージャー付きで実装できます。上記の私有財産コードとまったく同じです。スコープとそのシンボルを複数のプロトタイプと共有するだけです。

ただし、これは、モジュール全体を同じクローズドスコープで、つまり単一のファイルで定義する必要があるため、実用的ではありません。しかし、それでもそれはオプションです。

10
Sheepy

私はこれに答えるのが遅れていますが、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]()
  }
}
1
Twifty