過去10年間(Happy Birthday、prototype.js!)、JavaScriptで本格的なOOPをエミュレートするために多くのライブラリが作成されてきました。
いずれにせよ、クラスのプライベートメンバを実装する問題を解決しました。
多くの槍が壊れたため、開発者は2つの部分に分けられました。
最初のものはコンストラクターのスコープでプライベートプロパティを非表示にし、プロトタイプの使用を拒否します(オブジェクトの各インスタンスのメソッドを再度作成します)。
理論:
新しいキーワードを使用すると、プロトタイプメソッドを含む空のオブジェクトと同じになるように関数を呼び出すことができます。 したがって、コンストラクター内で、明示的にreturnを指定せずにコンストラクターから戻るオブジェクトを形成できます。
var Animal = function(name){ this._privateName = name; }; Animal.prototype.getName = function(){ return this._privateName; }; var a = new Animal('Cow'); a._privateName === a.getName(); /* true */
ただし、newで呼び出された関数がプリミティブ型(文字列、数値、NaNなど)以外の値を明示的に返す場合、この空のオブジェクトとメソッドがコンストラクター内で使用できるにもかかわらず、この結果が返されますプロトタイプから。
練習:
このすべてのプロパティがプライベートであると想定し、パブリックプロパティを明示的に返す場合、プライベートプロパティのエレガントなエミュレーションを取得します。
var Animal = function(name){ var self = this; this._privateName = name; return { hello: Animal.prototype.hello.bind(this) }; }; Animal.prototype.getName = function(){ return this._privateName; }; Animal.prototype.hello = function(){ return 'hello ' + this.getName(); }; var a = new Animal('Cow'); a._privateName; /* undefined */ a.getName(); /* Exception */ a.hello(); /* hello Cow */
たとえば、コンストラクタを「ラップ」し、プロトタイプからプライベートメソッドを隠す単純な関数を作成しました。
github.com/poluyanov/privatize/blob/master/privatize.js
長所:
- このアプローチの主な利点は、多数のオブジェクトで、プロトタイプとそのメソッドの操作が、オブジェクトの各インスタンスのメソッドの従来の作成よりも高速であることです: jsperf.com/scopevsprototype
- 多くのオブジェクトのプロトタイプメソッドを動的にオーバーライドすると便利な場合があります。
- プロトタイプ内では、多くのオブジェクト(たとえば、カウンター)の共通フィールドを隠すことができます(実際に!)。
短所:
- コンストラクター関数は単純なオブジェクトを返すため、instanceofは機能しません。
- このアプローチは、一部の人にとっては暗黙的で自明ではないように思えるかもしれません。
この方法は革新的なふりをするものではなく、おそらくあなたは仕事でこのアプローチをよく使用します。 あなたのコメントを歓迎します。