JavaScript ES6クラスのプライベートプロパティ


444

ES6クラスでプライベートプロパティを作成することは可能ですか?

ここに例があります。どうすればアクセスを防ぐことができますinstance.propertyか?

class Something {
  constructor(){
    this.property = "test";
  }
}

var instance = new Something();
console.log(instance.property); //=> "test"

5
この機能には実際にはステージ3の提案があります-tc39.github.io/proposal-class-fields github.com/tc39/proposal-class-fields
arty

@artyこれに対する例を挙げて回答を提供しました: stackoverflow.com/a/52237988/1432509
Alister

回答:


165

プライベートフィールド(およびメソッド)は、ECMA標準で実装されていますバベル7とステージ3のプリセットで今日から使用できます。

class Something {
  #property;

  constructor(){
    this.#property = "test";
  }

  #privateMethod() {
    return 'hello world';
  }

  getPrivateMessage() {
      return this.#privateMethod();
  }
}

const instance = new Something();
console.log(instance.property); //=> undefined
console.log(instance.privateMethod); //=> undefined
console.log(instance.getPrivateMessage()); //=> hello world

これらのクラスフィールドはどのように機能するのでしょうか。現在this、を呼び出す前にコンストラクターで使用することはできませんsuper()。しかし、バベルはスーパーの前にそれらを置きます。
seeker_of_bacon 2018年

#privateCrap構文を許可するようにESLintを構成する方法
Marecky 2018年

6
そして、エスリントはどうですか?等号でパーサーエラーが発生しました。Babelは動作していますが、eslintがこの新しいjs構文を解析できないだけです。
-martonx

6
うわーこれは非常に醜いです。ハッシュタグは有効な文字です。プロパティは本当にプライベートではありませんか?.. TypeScriptで確認しました。プライベートメンバーは、プライベートまたは読み取り専用(外部から)でコンパイルされません。別の(パブリック)プロパティのように宣言されています。(ES5)。
ドミニク

2
これでプライベートメソッドをどのように記述しますか?私はこれを行うことができます:#beep() {}; そしてこれ:async #bzzzt() {}
КонстантинВан

277

短い回答ですが、ES6クラスのプライベートプロパティはネイティブでサポートされていません。

ただし、オブジェクトに新しいプロパティをアタッチせずに、クラスコンストラクター内に保持することでその動作を模倣し、ゲッターとセッターを使用して非表示のプロパティにアクセスできます。ゲッターとセッターは、クラスの新しいインスタンスごとに再定義されることに注意してください。

ES6

class Person {
    constructor(name) {
        var _name = name
        this.setName = function(name) { _name = name; }
        this.getName = function() { return _name; }
    }
}

ES5

function Person(name) {
    var _name = name
    this.setName = function(name) { _name = name; }
    this.getName = function() { return _name; }
}

1
私はこのソリューションが一番好きです。スケーリングには使用しないでください。ただし、通常はインクルードごとに1回だけインスタンス化されるクラスに最適です。
Blake Regalia

2
また、新しいクラスが作成されるたびに、このクラスのすべてのコンポーネントを再定義しています。
Quentin Roy、

10
これはとても奇妙です!ES6では、ES6以前よりも多くの「閉鎖ピラミッド」を作成しています。コンストラクタ内で関数を定義すると、上記のES5の例よりも醜く見えます。
Kokodoko 2016年

1
OPは特にES6クラスについて質問するので、技術的には機能しますが、個人的にはこれは貧弱なソリューションだと思います。主な制限は、プライベート変数を使用するすべてのクラスメソッドをコンストラクター内で宣言する必要があることclassです。これにより、最初に構文を使用する利点が大幅に損なわれます。
NanoWizard 2017

10
これが行うことはすべて間接参照を導入することです。ではgetNamesetNameプロパティとプロパティをどのようにプライベートにしますか?
aij 2018

195

@loganfsmythの答えを拡張するには:

JavaScriptの唯一の真にプライベートなデータは、まだスコープ変数です。パブリックプロパティと同じ方法で内部的にアクセスされるプロパティの意味でプライベートプロパティを使用することはできませんが、スコープ付き変数を使用してプライベートデータを格納できます。

スコープ付き変数

ここでのアプローチは、プライベートであるコンストラクター関数のスコープを使用してプライベートデータを格納することです。メソッドがこのプライベートデータにアクセスできるようにするには、コンストラクタ内でもメソッドを作成する必要があります。つまり、すべてのインスタンスでメソッドを再作成します。これはパフォーマンスとメモリのペナルティですが、ペナルティは許容範囲であると信じている人もいます。通常どおりにプロトタイプに追加することで、プライベートデータにアクセスする必要のないメソッドのペナルティを回避できます。

例:

function Person(name) {
  let age = 20; // this is private
  this.name = name; // this is public

  this.greet = function () {
    // here we can access both name and age
    console.log(`name: ${this.name}, age: ${age}`);
  };
}

let joe = new Person('Joe');
joe.greet();

// here we can access name but not age

スコープ付きWeakMap

WeakMapを使用して、以前のアプローチのパフォーマンスとメモリのペナルティを回避できます。WeakMapは、そのWeakMapを使用しないとアクセスできない方法で、データをオブジェクト(ここではインスタンス)に関連付けます。したがって、スコープ変数メソッドを使用してプライベートWeakMapを作成し、そのWeakMapを使用してに関連付けられたプライベートデータを取得しますthis。すべてのインスタンスが1つのWeakMapを共有できるため、スコープ変数メソッドよりも高速です。そのため、独自のWeakMapにアクセスするためだけにメソッドを再作成する必要はありません。

例:

let Person = (function () {
  let privateProps = new WeakMap();

  class Person {
    constructor(name) {
      this.name = name; // this is public
      privateProps.set(this, {age: 20}); // this is private
    }

    greet() {
      // Here we can access both name and age
      console.log(`name: ${this.name}, age: ${privateProps.get(this).age}`);
    }
  }

  return Person;
})();

let joe = new Person('Joe');
joe.greet();

// here we can access joe's name but not age

この例では、オブジェクトを使用して、複数のプライベートプロパティに1つのWeakMapを使用しています。また、複数のWeakMapを使用してそれらをのようage.set(this, 20)に使用したり、小さなラッパーを作成して別の方法で使用したりすることもできますprivateProps.set(this, 'age', 0)

このアプローチのプライバシーは、理論的にはグローバルWeakMapオブジェクトを改ざんすることによって侵害される可能性があります。そうは言っても、すべてのJavaScriptはマングルされたグローバルによって破壊される可能性があります。私たちのコードは、これが起こらないことを前提にすでに構築されています。

(この方法は、でも実行できますが、非常に注意しない限り、メモリリークが発生するためMap、この方法のWeakMap方が優れてMapいます。この目的のために、この2つに違いはありません。)

半解答:スコープシンボル

シンボルは、プロパティ名として使用できるプリミティブ値の一種です。スコープ変数メソッドを使用してプライベートシンボルを作成し、プライベートデータをに格納できますthis[mySymbol]

このメソッドのプライバシーはを使用して侵害される可能性がありますがObject.getOwnPropertySymbols、行うのはやや厄介です。

例:

let Person = (function () {
  let ageKey = Symbol();

  class Person {
    constructor(name) {
      this.name = name; // this is public
      this[ageKey] = 20; // this is intended to be private
    }

    greet() {
      // Here we can access both name and age
      console.log(`name: ${this.name}, age: ${this[ageKey]}`);
    }
  }

  return Person;
})();

let joe = new Person('Joe');
joe.greet();

// Here we can access joe's name and, with a little effort, age. ageKey is
// not in scope, but we can obtain it by listing all Symbol properties on
// joe with `Object.getOwnPropertySymbols(joe)`.

半解答:アンダースコア

古いデフォルトでは、アンダースコアのプレフィックスが付いたパブリックプロパティを使用するだけです。プライベートプロパティではありませんが、この規則は広く普及しているため、読者がプロパティをプライベートとして扱う必要があることを伝え、仕事をこなすことができます。この失効と引き換えに、読みやすく、入力しやすく、より高速なアプローチが得られます。

例:

class Person {
  constructor(name) {
    this.name = name; // this is public
    this._age = 20; // this is intended to be private
  }

  greet() {
    // Here we can access both name and age
    console.log(`name: ${this.name}, age: ${this._age}`);
  }
}

let joe = new Person('Joe');
joe.greet();

// Here we can access both joe's name and age. But we know we aren't
// supposed to access his age, which just might stop us.

結論

ES2017の時点では、プライベートプロパティを実行する完璧な方法はまだありません。さまざまなアプローチには長所と短所があります。スコープ付き変数は本当にプライベートです。スコープ付きWeakMapは非常にプライベートであり、スコープ付き変数よりも実用的です。スコープ付きシンボルは、かなりプライベートで、かなり実用的です。アンダースコアは多くの場合十分にプライベートであり、非常に実用的です。


7
最初の例のスニペット(「スコープ変数」)は完全なアンチパターンです-返される各オブジェクトには異なるクラスがあります。それをしないでください。特権付きメソッドが必要な場合は、コンストラクターで作成します。
Bergi、2015年

1
関数内でクラスをラップすることは、そもそもクラスを使用するという目的全体を無効にするようです。関数を使用してインスタンスを作成している場合は、すべてのプライベート/パブリックメンバーをその関数内に配置し、クラスキーワード全体を忘れることもできます。
ココドコ

2
@Bergi @Kokodoko私はスコープ変数のアプローチを少し速く、壊れないように編集しましたinstanceof。私はそのアプローチが完全を期すためだけに含まれていると考えていたと認め、それが実際にどれだけ可能であるかについてもっと考えるべきだったと思います。
トリスタン

1
素晴らしい説明!ES6がプライベート変数のシミュレーションを実際に難しくしたことにまだ驚きます。ES5では関数内でvarとthisを使用するだけでプライベートとパブリックをシミュレートできました。
Kokodoko 2016年

2
@Kokodokoクラスを省略してすべてを関数に入れる場合は、プロトタイプメソッドを使用した継承の実装に戻す必要もあります。クラスで拡張を使用する方がはるかにクリーンなアプローチであるため、関数内でクラスを使用することは完全に許容されます。
AndroidDev 2017年

117

更新:より良い構文の提案が進んでいます。貢献は大歓迎です。


はい、そこにある- -オブジェクト内のスコープのアクセスのためにES6紹介Symbol

シンボルは一意であり、リフレクション(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

6
使えないのObject.getOwnPropertySymbols?;)
カンタス94ヘビー

41
@BenjaminGruenbaum:どうやらシンボルはもはや真のプライバシーを保証しません:stackoverflow.com/a/22280202/1282216
d13

28
鍵を介した@trusktr?いいえ。シンボルを介して?はい。C#やJavaなどの言語でリフレクションを使用してプライベートフィールドにアクセスする方法とよく似ています。アクセス修飾子はセキュリティに関するものではなく、意図の明確さに関するものです。
Benjamin Gruenbaum 2014年

9
Symbolsを使用することは、を実行することに似ているようですconst myPrivateMethod = Math.random(); Something.prototype[''+myPrivateMethod] = function () { ... } new Something()[''+myPrivateMethod]();。これは、実際のプライバシーではなく、従来のJavaScriptの意味でのあいまいさです。「プライベート」JavaScriptは、クロージャーを使用して変数をカプセル化することを意味すると考えます。したがって、これらの変数はリフレクションを通じてアクセスできません。
trusktr 2014年

13
また、キーワードを使用するprivateprotectedSymbolまたはよりもはるかにクリーンになると思いNameます。ブラケット表記よりもドット表記の方が好きです。プライベートにはドットを使い続けたいです。this.privateVar
trusktr 2014年

33

答えはノーだ"。ただし、次のようなプロパティへのプライベートアクセスを作成できます。

  • モジュールを使用します。exportキーワードを使用して公開しない限り、モジュール内のすべてがプライベートです。
  • モジュール内では、関数クロージャーを使用します:http : //www.kirupa.com/html5/closures_in_javascript.htm

(プライバシーを確​​保するためにシンボルを使用できるという提案は、ES6仕様の以前のバージョンでは真実でしたが、現在は当てはまりません:https : //mail.mozilla.org/pipermail/es-discuss/2014-January/035604。 htmlhttps://stackoverflow.com/a/22280202/1282216。シンボルとプライバシーの詳細については、https//curiosity-driven.org/private-properties-in-javascriptを参照してください


6
-1、これは実際にはあなたの質問に答えません。(ES5のIIFEでもクロージャーを使用できます)。プライベートプロパティは、ほとんどの言語(Java、C#など)でリフレクションを介して列挙できます。プライベートプロパティのポイントは、他のプログラマーに意図を伝えることであり、セキュリティを強制することではありません。
Benjamin

1
@BenjaminGruenbaum、私は知っている、私は私がより良い答えがあったらいいのに、私はそれにも満足していない。
d13

プログラミング環境では、シンボルは依然としてアクセスできないメンバーを実現する有効な方法だと思います。はい、必要に応じて見つけることができますが、それが目的ではありませんか?機密情報をそこに格納するべきではありませんが、クライアント側のコードでそれをとるべきではありません。ただし、外部クラスからプロパティまたはメソッドを隠す目的で機能します。
ココドコ2017年

モジュールのレベルでスコープされた変数をクラスのプライベートプロパティの代わりとして使用すると、statitcプロパティに似たsingleton.behaviorまたは動作が発生します。varのインスタンスは共有されます。
エイドリアンモイサ

30

JSで真のプライバシーを取得する唯一の方法はスコープを使用することです。そのため、そのメンバーであるプロパティthisにコンポーネント内でのみアクセスできるようにする方法はありません。真にプライベートなデータをES6に保存する最良の方法は、WeakMapを使用することです。

const privateProp1 = new WeakMap();
const privateProp2 = new WeakMap();

class SomeClass {
  constructor() {
    privateProp1.set(this, "I am Private1");
    privateProp2.set(this, "I am Private2");

    this.publicVar = "I am public";
    this.publicMethod = () => {
      console.log(privateProp1.get(this), privateProp2.get(this))
    };        
  }

  printPrivate() {
    console.log(privateProp1.get(this));
  }
}

明らかにこれはおそらく遅く、明らかに醜いですが、プライバシーを提供します。

JavaScriptは非常に動的であるため、これも完璧ではないことに注意してください。誰かがまだできる

var oldSet = WeakMap.prototype.set;
WeakMap.prototype.set = function(key, value){
    // Store 'this', 'key', and 'value'
    return oldSet.call(this, key, value);
};

それらが保存されているとして、あなたが余分に慎重になりたい場合はキャッチ値に、そう、あなたはローカル参照をキャプチャする必要があるだろう.set.getオーバーライドプロトタイプに頼るので明示的に代わりに使用します。

const {set: WMSet, get: WMGet} = WeakMap.prototype;

const privateProp1 = new WeakMap();
const privateProp2 = new WeakMap();

class SomeClass {
  constructor() {
    WMSet.call(privateProp1, this, "I am Private1");
    WMSet.call(privateProp2, this, "I am Private2");

    this.publicVar = "I am public";
    this.publicMethod = () => {
      console.log(WMGet.call(privateProp1, this), WMGet.call(privateProp2, this))
    };        
  }

  printPrivate() {
    console.log(WMGet.call(privateProp1, this));
  }
}

3
提案として、オブジェクトを値として使用することで、プロパティごとに1つの弱いマップを使用しないようにすることができます。このように、マップの数をgetメソッドごとに1つに減らすこともできます(例:)const _ = privates.get(this); console.log(_.privateProp1);
Quentin Roy

うん、それも完全にオプションです。実際のプロパティを使用するときにユーザーが書いたものに、より直接的に対応するので、私はほとんどこれを使いました。
loganfsmyth 2015年

@loganfsmyth const myObj = new SomeClass(); console.log(privateProp1.get(myObj)) // "I am Private1"それはあなたの財産が私的であるかどうかを意味しますか?
Barbu Barbu

2
仕事に、プロパティにアクセスするコードは、通常、モジュールの内部とアクセスできないスコープされるだろうWeakMapオブジェクトへのアクセス必要があることについて
loganfsmyth

22

他のLookerを将来参照するために、WeakMapを使用してプライベートデータを保持することをお勧めしていると聞いています。

以下は、より明確で実用的な例です。

function storePrivateProperties(a, b, c, d) {
  let privateData = new WeakMap;
  // unique object as key, weak map can only accept object as key, when key is no longer referened, garbage collector claims the key-value 
  let keyA = {}, keyB = {}, keyC = {}, keyD = {};

  privateData.set(keyA, a);
  privateData.set(keyB, b);
  privateData.set(keyC, c);
  privateData.set(keyD, d);

  return {
    logPrivateKey(key) {
      switch(key) {
      case "a":
        console.log(privateData.get(keyA));
        break;
      case "b":
        console.log(privateData.get(keyB));
        break;
      case "c":
        console.log(privateData.get(keyC));
        break;
      case "d":
        console.log(privateData.set(keyD));
        break;
      default:
        console.log(`There is no value for ${key}`)
      }
    }
  }
}

20
これらのプロパティは静的であることに注意してください。
マイケルセリオット2015年

8
私はあなたに反対票を投じませんでしたが、あなたのウィークマップの例は完全に間違っています。
Benjamin Gruenbaum 2015

4
つまり、インスタンスごとではなく、すべてのクラスインスタンス間でデータを共有しています-少なくともそれを修正できますか?
Benjamin Gruenbaum 2015

1
実際、weakmapは特定のインスタンスにアタッチする必要があります。例については、fitzgeraldnick.com / weblog / 53を参照してください。
2015

2
MDNによれば、シンボルなどのプリミティブデータタイプはWeakMapキーとして許可されていません。MDN WeakMapのドキュメント
leepowell

12

あなたが尋ねる人に依存します :-)

privateプロパティの修飾子は、現在のドラフトに採用されたように見える、最小限のクラスの提案には含まれていません。

ただし、プライベートプロパティを許可するプライベート名のサポート が存在する可能性があり、おそらくクラス定義でも使用できます。


3
それはです非常に ES7のための民間のもののいくつかのフォームの彼らだ思考ものの、民間名前はES6にそれを作るとは考えにくいです。
Qantas 94ヘビー

@ Qantas94私が理解していることから、プライベート名と一意の文字列値の両方がシンボルに置き換えられました。
Benjamin Gruenbaum 2014年

ええ、それはおそらくシンボルになるでしょう。ただし、現在仕様に含まれている「シンボル」は、[[prototype]]のような内部プロパティを記述するためにのみ使用され、ユーザーコードで作成して使用する方法はありません。あなたはいくつかのドキュメントを知っていますか?
Bergi

モジュールを使用してプライバシーを設定できることに気づきました。必要なだけのシンボルと組み合わせる...?
d13 2014年

1
@Cody:いずれにしても、ES6ではモジュールコード全体に独自のスコープがあり、IEFEは必要ありません。そして、はい、シンボルはプライバシーではなく、一意性(衝突回避)を目的としています。
Bergi

10

ES6モジュール(最初は@ d13によって提案されました)を使用するとうまくいきます。プライベートプロパティを完全に模倣するわけではありませんが、少なくともプライベートであるはずのプロパティがクラスの外部にリークしないことを確信できます。次に例を示します。

something.js

let _message = null;
const _greet = name => {
  console.log('Hello ' + name);
};

export default class Something {
  constructor(message) {
    _message = message;
  }

  say() {
    console.log(_message);
    _greet('Bob');
  }
};

その場合、使用するコードは次のようになります。

import Something from './something.js';

const something = new Something('Sunny day!');
something.say();
something._message; // undefined
something._greet(); // exception

更新(重要):

@DanyalAytekinがコメントで概説されているように、これらのプライベートプロパティは静的であるため、スコープはグローバルです。シングルトンを使用する場合は問題なく動作しますが、一時オブジェクトには注意が必要です。上記の例を拡張すると:

import Something from './something.js';
import Something2 from './something.js';

const a = new Something('a');
a.say(); // a

const b = new Something('b');
b.say(); // b

const c = new Something2('c');
c.say(); // c

a.say(); // c
b.say(); // c
c.say(); // c

4
に適していprivate staticます。
Danyal Aytekin

@DanyalAytekin:それは非常に良い点です。これらのプライベートプロパティは静的であるため、スコープはグローバルです。これを反映するように回答を更新しました。
Johnny

関数型プログラミング(特にElmとHaskell)について学べば学ぶほど、JSプログラマーはOOPクラスベースではなく、モジュールベースの「モジュール性」へのアプローチから恩恵を受けると信じています。ES6モジュールをアプリケーション構築の基礎と考え、クラスを完全に忘れた場合、アプリケーション全体がはるかに優れたものになると思います。ElmまたはHaskellの経験豊富なユーザーがこのアプローチについてコメントできますか?
d13

1
アップデートでは、2番目a.say(); // ab.say(); // b
Grokky

let _message = null方法を試しましたが、それほどクールではありません。コンストラクタを複数回呼び出すと、失敗します。
Littlee 2018年

9

@ d13と、@ johnny-oshikaと@DanyalAytekinによるコメントを完成させます。

@ johnny-oshikaが提供する例では、矢印関数の代わりに通常の関数を使用.bindし、現在のオブジェクトと_privatesカリー化されたパラメータとしてオブジェクトを使用することができると思います:

something.js

function _greet(_privates) {
  return 'Hello ' + _privates.message;
}

function _updateMessage(_privates, newMessage) {
  _privates.message = newMessage;
}

export default class Something {
  constructor(message) {
    const _privates = {
      message
    };

    this.say = _greet.bind(this, _privates);
    this.updateMessage = _updateMessage.bind(this, _privates);
  }
}

main.js

import Something from './something.js';

const something = new Something('Sunny day!');

const message1 = something.say();
something.updateMessage('Cloudy day!');
const message2 = something.say();

console.log(message1 === 'Hello Sunny day!');  // true
console.log(message2 === 'Hello Cloudy day!');  // true

// the followings are not public
console.log(something._greet === undefined);  // true
console.log(something._privates === undefined);  // true
console.log(something._updateMessage === undefined);  // true

// another instance which doesn't share the _privates
const something2 = new Something('another Sunny day!');

const message3 = something2.say();

console.log(message3 === 'Hello another Sunny day!'); // true

私が考えることができる利点:

  • 私たちはプライベートメソッドを持つことができます(_greetそして参照_updateMessageがない限りプライベートメソッドのように振る舞いexportます)
  • プロトタイプにはありませんが、上記のメソッドはインスタンスをクラスの外で(コンストラクターで定義するのではなく)1回作成するため、メモリを節約できます。
  • モジュール内にいるため、グローバルをリークしません
  • バインドされた_privatesオブジェクトを使用してプライベートプロパティを持つこともできます

私が考えることができるいくつかの欠点:

実行中のスニペットはここにあります:http : //www.webpackbin.com/NJgI5J8lZ


8

はい-カプセル化されたプロパティを作成できますが、少なくともES6ではアクセス修飾子(public | private)を使用して行われていません。

ES6でこれを行う方法の簡単な例を次に示します。

1 クラスワードを使用してクラスを作成する

2そのコンストラクターの内部では、let OR const予約語を使用してブロックスコープ変数を宣言します->それらはブロックスコープであるため、外部からアクセスできません(カプセル化)

3これらの変数へのアクセス制御(セッター|ゲッター)を許可するには、次のthis.methodName=function(){}構文を使用して、コンストラクター内でインスタンスメソッドを宣言できます。

"use strict";
    class Something{
        constructor(){
            //private property
            let property="test";
            //private final (immutable) property
            const property2="test2";
            //public getter
            this.getProperty2=function(){
                return property2;
            }
            //public getter
            this.getProperty=function(){
                return property;
            }
            //public setter
            this.setProperty=function(prop){
                property=prop;
            }
        }
    }

それを確認しましょう:

var s=new Something();
    console.log(typeof s.property);//undefined 
    s.setProperty("another");//set to encapsulated `property`
    console.log(s.getProperty());//get encapsulated `property` value
    console.log(s.getProperty2());//get encapsulated immutable `property2` value

1
これは(現時点では)コンストラクターで宣言されたすべてのメソッドがクラスのインスタンスごとに再宣言されるという事実にもかかわらず、この問題の唯一の解決策です。これは、パフォーマンスとメモリ使用量に関してかなり悪い考えです。クラスメソッドは、コンストラクタスコープ外で宣言する必要があります。
2016

@Freezystem最初:最初はインスタンスメソッドです(クラスメソッドではありません)。第二に _私はinstance.property?_へのアクセスを防止するにはどうすればよいと私の答えは次のとおりです:OPの質問でしたか...の例 第三は、あなたが任意のより良いアイデアを持っている場合-のは、それを聞いてみましょう
ニキータKurtin

1
あなたが間違っていると言ったのではありません。new Something();コンストラクターでメソッドがこれらにアクセスできるように宣言されているため、呼び出すたびに各インスタンスメソッドのコピーが作成されるにもかかわらず、プライベート変数を実現するための最善の妥協案はあなたのソリューションであると言いましたプライベート変数。クラスのインスタンスを大量に作成すると、大量のメモリが消費され、パフォーマンスの問題が発生する可能性があります。メソッドはコンストラクタのスコープ外で宣言されている必要があります。私のコメントは、批判よりもソリューションの欠点の説明でした。
Freezystem 2016

1
しかし、悪い習慣は、コンストラクター内でクラス全体を定義することではないでしょうか?私たちは今、JavaScriptを「ハッキング」しているだけではありませんか?他のOOPプログラミング言語を見ると、コンストラクターがクラスを定義するためのものではないことがわかります。
Kokodoko 2016年

1
はい、それが私の意図したことであり、あなたの解決策は機能します!ES6が 'class'キーワードを追加したことに驚いたが、カプセル化を実現するために、varとthisを使用するエレガントなソリューションを削除したことを私はただ単に言っているだけです。
Kokodoko 2016年

8

「プライベート」への別のアプローチ

ES6ではプライベートの可視性が現在利用できないという事実に対抗する代わりに、IDEがJSDoc(例:Webstorm)をサポートしている場合は問題ない、より実用的なアプローチを取ることにしました。アイデアは、@privateタグを使用することです。開発に関する限り、IDEでは、クラスの外部からプライベートメンバーにアクセスすることはできません。私にとっては非常にうまく機能し、内部メソッドを非表示にするのに非常に便利なので、オートコンプリート機能は、クラスが実際に公開するつもりだったものを表示します。次に例を示します。

公開コンテンツのみを表示するオートコンプリート


1
問題は、エディターを介してプライベート変数にアクセスしたくないこと、プライベート変数を外部から保護したくないことです。つまり、パブリック/プライベートが何をするかです。コードが完成したら、クラスの外部からこれらの変数にアクセスすることができます(重要な考え:オーバーライド)。あなたの@privateコメントはこれらを防ぐことはできません、それはドキュメンテーション生成のための機能であり、あなたのIDEです。
エイドリアンPreuss

はい、承知しています。それは私にとって十分であり、そこにいる他の人々にとっては十分かもしれないということだけです。変数が実際にはプライベートにならないことはわかっています。外部からアクセスしないように警告するだけです(もちろん、私のチームと私がこの機能をサポートするIDEを使用している場合のみです)。JavaScript(およびPythonなどの他の言語)は、アクセスレベルを考慮して設計されていません。人々は何らかの形でその機能を実装するためにあらゆる種類のことをしますが、結局、それを実現するために言語をハッキングするだけです。可能であれば、もっと「自然な」アプローチを採用することにしました。
ルシオパイヴァ

6

WeakMap

  • IE11でサポート(記号はサポートされていません)
  • プライベート・ハード(シンボルを使用した小道具がソフト民間によるものですObject.getOwnPropertySymbols
  • (コンストラクタのすべての小道具とメソッドを必要とするクロージャとは異なり)本当にきれいに見えることができます

まず、WeakMapをラップする関数を定義します。

function Private() {
  const map = new WeakMap();
  return obj => {
    let props = map.get(obj);
    if (!props) {
      props = {};
      map.set(obj, props);
    }
    return props;
  };
}

次に、クラスの外部で参照を作成します。

const p = new Private();

class Person {
  constructor(name, age) {
    this.name = name;
    p(this).age = age; // it's easy to set a private variable
  }

  getAge() {
    return p(this).age; // and get a private variable
  }
}

注:クラスはIE11ではサポートされていませんが、例では見た目がきれいです。


6

ああ、非常に多くのエキゾチックなソリューション!私が使用するので、私は通常、プライバシーを気にしない「疑似プライバシーを」それはのようここに述べました。しかし、気にかける場合(そのための特別な要件がある場合)、この例のようなものを使用します。

class jobImpl{
  // public
  constructor(name){
    this.name = name;
  }
  // public
  do(time){
    console.log(`${this.name} started at ${time}`);
    this.prepare();
    this.execute();
  }
  //public
  stop(time){
    this.finish();
    console.log(`${this.name} finished at ${time}`);
  }
  // private
  prepare(){ console.log('prepare..'); }
  // private
  execute(){ console.log('execute..'); }
  // private
  finish(){ console.log('finish..'); }
}

function Job(name){
  var impl = new jobImpl(name);
  return {
    do: time => impl.do(time),
    stop: time => impl.stop(time)
  };
}

// Test:
// create class "Job"
var j = new Job("Digging a ditch");
// call public members..
j.do("08:00am");
j.stop("06:00pm");

// try to call private members or fields..
console.log(j.name); // undefined
j.execute(); // error

関数(コンストラクター)の別の可能な実装Job

function Job(name){
  var impl = new jobImpl(name);
  this.do = time => impl.do(time),
  this.stop = time => impl.stop(time)
}

5

個人的にはバインド演算子の 提案が好きで、::それを前述のソリューション@ d13と組み合わせますが、今のところexport、クラスのキーワードを使用してモジュールにプライベート関数を配置する@ d13の回答に固執します。

ここでは触れられていない、より機能的なアプローチであり、クラス内にすべてのプライベートプロップ/メソッドを持つことができる、もう1つの難しいソリューションがあります。

Private.js

export const get = state => key => state[key];
export const set = state => (key,value) => { state[key] = value; }

Test.js

import { get, set } from './utils/Private'
export default class Test {
  constructor(initialState = {}) {
    const _set = this.set = set(initialState);
    const _get = this.get = get(initialState);

    this.set('privateMethod', () => _get('propValue'));
  }

  showProp() {
    return this.get('privateMethod')();
  }
}

let one = new Test({ propValue: 5});
let two = new Test({ propValue: 8});
two.showProp(); // 8
one.showProp(); // 5

それについてのコメントをいただければ幸いです。


一般的に私はアプローチが好きです。フィードバック:1.衝突を防ぐために、クラスごとに異なるprivate.jsモジュールが必要です。2.各プライベートメソッドをインラインで定義することにより、コンストラクタを非常に長くする可能性を嫌います。3.すべてのクラスメソッドが1つのファイルにあると便利です。
Doug Coburn 2017年

5

「クラスのプライベートデータ」のベストプラクティスを探しているときに、この投稿を見つけました。いくつかのパターンにはパフォーマンスの問題があると述べられました。

オンラインブック「Exploring ES6」の4つの主要なパターンに基づいて、いくつかのjsperfテストをまとめました。

http://exploringjs.com/es6/ch_classes.html#sec_private-data-for-classes

テストはここにあります:

https://jsperf.com/private-data-for-classes

Chrome 63.0.3239 / Mac OS X 10.11.6では、最高のパフォーマンスパターンは、「コンストラクター環境を介したプライベートデータ」と「命名規則を介したプライベートデータ」でした。私にとって、SafariはWeakMapでうまく機能しましたが、Chromeはそれほどうまくいきませんでした。

メモリへの影響はわかりませんが、パフォーマンスの問題であると警告された「コンストラクタ環境」のパターンは非常に高性能でした。

4つの基本パターンは次のとおりです。

コンストラクター環境を介したプライベートデータ

class Countdown {
    constructor(counter, action) {
        Object.assign(this, {
            dec() {
                if (counter < 1) return;
                counter--;
                if (counter === 0) {
                    action();
                }
            }
        });
    }
}
const c = new Countdown(2, () => {});
c.dec();
c.dec();

コンストラクター環境2によるプライベートデータ

class Countdown {
    constructor(counter, action) {
        this.dec = function dec() {
            if (counter < 1) return;
            counter--;
            if (counter === 0) {
                action();
            }
        }
    }
}
const c = new Countdown(2, () => {});
c.dec();
c.dec();

命名規則によるプライベートデータ

class Countdown {
    constructor(counter, action) {
        this._counter = counter;
        this._action = action;
    }
    dec() {
        if (this._counter < 1) return;
        this._counter--;
        if (this._counter === 0) {
            this._action();
        }
    }
}
const c = new Countdown(2, () => {});
c.dec();
c.dec();

WeakMapsによるプライベートデータ

const _counter = new WeakMap();
const _action = new WeakMap();
class Countdown {
    constructor(counter, action) {
        _counter.set(this, counter);
        _action.set(this, action);
    }
    dec() {
        let counter = _counter.get(this);
        if (counter < 1) return;
        counter--;
        _counter.set(this, counter);
        if (counter === 0) {
            _action.get(this)();
        }
    }
}
const c = new Countdown(2, () => {});
c.dec();
c.dec();

シンボルによるプライベートデータ

const _counter = Symbol('counter');
const _action = Symbol('action');

class Countdown {
    constructor(counter, action) {
        this[_counter] = counter;
        this[_action] = action;
    }
    dec() {
        if (this[_counter] < 1) return;
        this[_counter]--;
        if (this[_counter] === 0) {
            this[_action]();
        }
    }
}
const c = new Countdown(2, () => {});
c.dec();
c.dec();

4

私は、コンストラクター内のクロージャーを使用して「両方の長所」を得ることが可能であると信じています。2つのバリエーションがあります。

すべてのデータメンバーはプライベートです

function myFunc() {
   console.log('Value of x: ' + this.x);
   this.myPrivateFunc();
}

function myPrivateFunc() {
   console.log('Enhanced value of x: ' + (this.x + 1));
}

class Test {
   constructor() {

      let internal = {
         x : 2,
      };
      
      internal.myPrivateFunc = myPrivateFunc.bind(internal);
      
      this.myFunc = myFunc.bind(internal);
   }
};

一部のメンバーは非公開です

注:これは確かに醜いです。より良い解決策を知っている場合は、この応答を編集してください。

function myFunc(priv, pub) {
   pub.y = 3; // The Test object now gets a member 'y' with value 3.
   console.log('Value of x: ' + priv.x);
   this.myPrivateFunc();
}

function myPrivateFunc() {
   pub.z = 5; // The Test object now gets a member 'z' with value 3.
   console.log('Enhanced value of x: ' + (priv.x + 1));
}

class Test {
   constructor() {
      
      let self = this;

      let internal = {
         x : 2,
      };
      
      internal.myPrivateFunc = myPrivateFunc.bind(null, internal, self);
      
      this.myFunc = myFunc.bind(null, internal, self);
   }
};


4

実際、シンボルとプロキシを使用することは可能です。クラススコープでシンボルを使用し、プロキシに2つのトラップを設定します。1つはクラスプロトタイプ用で、Reflect.ownKeys(instance)またはObject.getOwnPropertySymbolsがシンボルを提供しないようにします。もう1つはコンストラクタ自体用です。したがって、new ClassName(attrs)が呼び出されると、返されたインスタンスがインターセプトされ、独自のプロパティシンボルがブロックされます。コードは次のとおりです。

const Human = (function() {
  const pet = Symbol();
  const greet = Symbol();

  const Human = privatizeSymbolsInFn(function(name) {
    this.name = name; // public
    this[pet] = 'dog'; // private 
  });

  Human.prototype = privatizeSymbolsInObj({
    [greet]() { // private
      return 'Hi there!';
    },
    revealSecrets() {
      console.log(this[greet]() + ` The pet is a ${this[pet]}`);
    }
  });

  return Human;
})();

const bob = new Human('Bob');

console.assert(bob instanceof Human);
console.assert(Reflect.ownKeys(bob).length === 1) // only ['name']
console.assert(Reflect.ownKeys(Human.prototype).length === 1 ) // only ['revealSecrets']


// Setting up the traps inside proxies:
function privatizeSymbolsInObj(target) { 
  return new Proxy(target, { ownKeys: Object.getOwnPropertyNames });
}

function privatizeSymbolsInFn(Class) {
  function construct(TargetClass, argsList) {
    const instance = new TargetClass(...argsList);
    return privatizeSymbolsInObj(instance);
  }
  return new Proxy(Class, { construct });
}

Reflect.ownKeys()Object.getOwnPropertyNames(myObj).concat(Object.getOwnPropertySymbols(myObj))そのように機能します。そのため、これらのオブジェクトのトラップが必要です。


ありがとう、シンボルを試してみます:)上記のすべての回答から、アクセスできないクラスメンバーを作成する最も簡単な方法のようです:)
Kokodoko

4

Typescriptでもできません。彼らのドキュメントから:

メンバーがプライベートとしてマークされている場合、そのメンバーであるクラスの外部からはアクセスできません。例えば:

class Animal {
    private name: string;
    constructor(theName: string) { this.name = theName; }
}

new Animal("Cat").name; // Error: 'name' is private;

しかし、彼らの遊び場で蒸散すると、次のようになります。

var Animal = (function () {
    function Animal(theName) {
        this.name = theName;
    }
    return Animal;
}());
console.log(new Animal("Cat").name);

したがって、「プライベート」キーワードは効果がありません。


2
まあ、それはIDEでの「悪い」プログラミングを防ぐので、それでも効果的です。使用すべきメンバーと使用すべきでないメンバーが表示されます。それが私用と公用の主な理由だと思います。(たとえば、C#をマシンコードにコンパイルしても、privateはまだprivateでしょうか?誰が知っていますか?)他の回答を読んでいるときに、@ Symbolを使用すると、メンバーにアクセスできなくなる可能性もあります。しかし、シンボルでさえコンソールから見つけることができます。
ココドコ2017年

TypeScriptからJavaScriptへのトランスパイル中にTypeScriptエラーは発生しますか?(型チェックと同様に、一時的に発生します。実行時のプライベートメカニズムではあり
ません

4

このパーティーには非常に遅れていますが、検索でOPの質問にヒットしました... はい、クラス宣言をクロージャーでラップすることにより、プライベートプロパティを持つことができます

このcodepenにプライベートメソッドがある方法の例があります。以下のスニペットでは、Subscribableクラスに2つの「プライベート」関数processとがありprocessCallbacksます。プロパティはこの方法で追加でき、クロージャーを使用することでプライベートに保たれます。懸念が十分に分離されていて、クロージャがきちんと機能しているときに、Javascriptが構文を追加することで肥大化する必要がない場合、IMOプライバシーはまれな必要です。

const Subscribable = (function(){

  const process = (self, eventName, args) => {
    self.processing.set(eventName, setTimeout(() => processCallbacks(self, eventName, args)))};

  const processCallbacks = (self, eventName, args) => {
    if (self.callingBack.get(eventName).length > 0){
      const [nextCallback, ...callingBack] = self.callingBack.get(eventName);
      self.callingBack.set(eventName, callingBack);
      process(self, eventName, args);
      nextCallback(...args)}
    else {
      delete self.processing.delete(eventName)}};

  return class {
    constructor(){
      this.callingBack = new Map();
      this.processing = new Map();
      this.toCallbacks = new Map()}

    subscribe(eventName, callback){
      const callbacks = this.unsubscribe(eventName, callback);
      this.toCallbacks.set(eventName,  [...callbacks, callback]);
      return () => this.unsubscribe(eventName, callback)}  // callable to unsubscribe for convenience

    unsubscribe(eventName, callback){
      let callbacks = this.toCallbacks.get(eventName) || [];
      callbacks = callbacks.filter(subscribedCallback => subscribedCallback !== callback);
      if (callbacks.length > 0) {
        this.toCallbacks.set(eventName, callbacks)}
      else {
        this.toCallbacks.delete(eventName)}
      return callbacks}

    emit(eventName, ...args){
      this.callingBack.set(eventName, this.toCallbacks.get(eventName) || []);
      if (!this.processing.has(eventName)){
        process(this, eventName, args)}}}})();

私はこのアプローチが好きです。懸念をうまく分離し、物事を本当にプライベートに保つからです。唯一の欠点は、プライベートコンテンツで「これ」を参照するために「自己」(または類似の何か)を使用する必要があることです。


4

ベンジャミンの答えは、言語が明示的にプライベート変数をネイティブでサポートするまで、ほとんどの場合におそらく最良だと思います。

ただし、何らかの理由ででのアクセスを防止する必要がある場合、Object.getOwnPropertySymbols()私が使用を検討した方法は、構築時に各オブジェクトのプロパティ識別子として使用できる、一意で構成、列挙、書き込みができないプロパティをアタッチすることです(のようなSymbol他の固有のプロパティがまだない場合は、uniqueのようなid)。次に、その識別子を使用して、各オブジェクトの「プライベート」変数のマップを保持します。

const privateVars = {};

class Something {
    constructor(){
        Object.defineProperty(this, '_sym', {
            configurable: false,
            enumerable: false,
            writable: false,
            value: Symbol()
        });

        var myPrivateVars = {
            privateProperty: "I'm hidden"
        };

        privateVars[this._sym] = myPrivateVars;

        this.property = "I'm public";
    }

    getPrivateProperty() {
        return privateVars[this._sym].privateProperty;
    }

    // A clean up method of some kind is necessary since the
    // variables won't be cleaned up from memory automatically
    // when the object is garbage collected
    destroy() {
        delete privateVars[this._sym];
    }
}

var instance = new Something();
console.log(instance.property); //=> "I'm public"
console.log(instance.privateProperty); //=> undefined
console.log(instance.getPrivateProperty()); //=> "I'm hidden"

使用に対するこのアプローチの潜在的な利点がWeakMapある高速なアクセス時間パフォーマンスが問題になった場合。


1
私が間違っている場合は修正してください。ただし、オブジェクトが既に破棄されている場合でも、privateVarsはオブジェクトのプライベート変数を格納するため、このコードにはメモリリークが含まれていませんか?
Russell Santos

@RussellSantos正解です。オブジェクトをある時点でガベージコレクションする必要があると想定しています。指摘いただきありがとうございます。私の例ではdestroy()、オブジェクトを削除する必要がある場合に使用コードによって呼び出されるメソッドを追加しました。
NanoWizard 2017

4

はい、まったくできますし、かなり簡単にできます。これは、コンストラクターでプロトタイプオブジェクトグラフを返すことにより、プライベート変数と関数を公開することで行われます。これは新しいことではありませんが、その優雅さを理解するために少しjs fooを取ってください。この方法では、グローバルスコープ、またはウィークマップを使用しません。言語に組み込まれたリフレクションの形式です。これをどのように活用するかによります。呼び出しスタックに割り込む例外を強制するか、例外をとして埋め込むことができますundefined。これは以下に示されています。これらの機能の詳細については、こちらをご覧ください。

class Clazz {
  constructor() {
    var _level = 1

    function _private(x) {
      return _level * x;
    }
    return {
      level: _level,
      public: this.private,
      public2: function(x) {
        return _private(x);
      },
      public3: function(x) {
        return _private(x) * this.public(x);
      },
    };
  }

  private(x) {
    return x * x;
  }
}

var clazz = new Clazz();

console.log(clazz._level); //undefined
console.log(clazz._private); // undefined
console.log(clazz.level); // 1
console.log(clazz.public(1)); //1
console.log(clazz.public2(2)); //2
console.log(clazz.public3(3)); //27
console.log(clazz.private(0)); //error


3
class Something {
  constructor(){
    var _property = "test";
    Object.defineProperty(this, "property", {
        get: function(){ return _property}
    });
  }
}

var instance = new Something();
console.log(instance.property); //=> "test"
instance.property = "can read from outside, but can't write";
console.log(instance.property); //=> "test"

2
コードのみの回答は避けるのが最善です。あなたのコードはOPの質問に答える方法を説明できれば良いだろう
Stewart_R

これは実際には、読み取り専用変数をプライベート変数よりも多くする方法です。プライベート変数は外部からアクセス可能であってはなりません。 console.log(instance.property)「テスト」を返さないでください。
oooyaya 2017

3

投稿された最後の2つに似た別の方法

class Example {
  constructor(foo) {

    // privates
    const self = this;
    this.foo = foo;

    // public interface
    return self.public;
  }

  public = {
    // empty data
    nodata: { data: [] },
    // noop
    noop: () => {},
  }

  // everything else private
  bar = 10
}

const test = new Example('FOO');
console.log(test.foo); // undefined
console.log(test.noop); // { data: [] }
console.log(test.bar); // undefined

2

ほとんどの回答は不可能であるか、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

このメソッドをアクセサパターンと呼びます。基本的なアイデアは、我々が持っているということであるクロージャキー閉鎖内部を、私たちが作成したプライベートオブジェクトあなたが持っている場合にのみアクセスすることができます(コンストラクタで)キーを

興味があれば、私の記事でこれについてもっと読むことができます。このメソッドを使用すると、クロージャーの外からアクセスできないオブジェクトごとのプロパティを作成できます。したがって、コンストラクタまたはプロトタイプで使用できますが、他の場所では使用できません。この方法がどこで使用されるかは知りませんが、本当に強力だと思います。


問題は、ES6クラスでこれを実現する方法についてでした。
Michael Franzl 2017

ES6クラスでもまったく同じメソッドを使用できます。ES6クラスは、主に、私の例で示したような関数の上にある砂糖です。オリジナルのポスターがトランスパイラーを使用している可能性は十分にあります。その場合、WeakMapsまたはSymbolsはポリフィルを必要とします。私の答えは関係なく有効です。
Guitarino

2

プライベートインターフェイスとパブリックインターフェイス、および構成のサポートを備えたクリーンでシンプルな「クラス」ソリューションについては、この回答を参照してください


2

私は非常に単純な解決策を見つけましたObject.freeze()。もちろん問題は、後でオブジェクトに何も追加できないことです。

class Cat {
    constructor(name ,age) {
        this.name = name
        this.age = age
        Object.freeze(this)
    }
}

let cat = new Cat('Garfield', 5)
cat.age = 6 // doesn't work, even throws an error in strict mode

これにより、次のようなセッターメソッドも無効になりますsetName(name) { this.name = name; }
ngakak 2018年

2

私はこのパターンを使用し、それは常に私のために働いています

class Test {
    constructor(data) {
        class Public {
            constructor(prv) {

                // public function (must be in constructor on order to access "prv" variable)
                connectToDb(ip) {
                    prv._db(ip, prv._err);
                } 
            }

            // public function w/o access to "prv" variable
            log() {
                console.log("I'm logging");
            }
        }

        // private variables
        this._data = data;
        this._err = function(ip) {
            console.log("could not connect to "+ip);
        }
    }

    // private function
    _db(ip, err) {
        if(!!ip) {
		    console.log("connected to "+ip+", sending data '"+this.data+"'");
			return true;
		}
        else err(ip);
    }
}



var test = new Test(10),
		ip = "185.167.210.49";
test.connectToDb(ip); // true
test.log(); // I'm logging
test._err(ip); // undefined
test._db(ip, function() { console.log("You have got hacked!"); }); // undefined


2

実際に可能です。
1.まず、クラスを作成し、コンストラクターで呼び出された_public関数を返します。
2.呼び出された_public関数で、this参照を渡します(すべてのプライベートメソッドとプロップへのアクセスを取得します)、およびからのすべての引数constructor (渡されますnew Names()
3. _public関数スコープには、(_ this Namesへのアクセス権を持つクラスもあります。this)プライベートNamesクラスの参照

class Names {
  constructor() {
    this.privateProperty = 'John';
    return _public(this, arguments);
  }
  privateMethod() { }
}

const names = new Names(1,2,3);
console.log(names.somePublicMethod); //[Function]
console.log(names.publicProperty); //'Jasmine'
console.log(names.privateMethod); //undefined
console.log(names.privateProperty); //undefind

function _public(_this, _arguments) {
  class Names {
    constructor() {
      this.publicProperty = 'Jasmine';
      _this.privateProperty; //"John";
      _this.privateMethod; //[Function]
    }

    somePublicMethod() {
      _this.privateProperty; //"John";
      _this.privateMethod; //[Function]
    }

  }
  return new Names(..._arguments);
}

2

あなたはこれを試すことができますhttps://www.npmjs.com/package/private-members

このパッケージはインスタンスごとにメンバーを保存します。

const pvt = require('private-members');
const _ = pvt();

let Exemplo = (function () {    
    function Exemplo() {
        _(this).msg = "Minha Mensagem";
    }

    _().mensagem = function() {
        return _(this).msg;
    }

    Exemplo.prototype.showMsg = function () {
        let msg = _(this).mensagem();
        console.log(msg);
    };

    return Exemplo;
})();

module.exports = Exemplo;
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.