ホームページ > 記事 > ウェブフロントエンド > JavaScript シミュレーション クラスのメカニズムとプライベート変数
一部のJavaScriptフレームワークを使用している場合、同様のコードが表示される場合があります
var MyClass = new Class({
initialize: function(param, ...) {
this.param = param;
...
} ,
func1 : function(...) {
...
}
});
var myObj = new MyClass(param);
myObj.func1(...);
これは典型的なオブジェクト指向ですクラス メカニズム アプリケーションは、ネイティブ JavaScript クラス メカニズムよりも明確で自然です。さらに、これに基づいて、クラス継承を実装するとさらに便利になります。では、これはどのようにして達成されるのでしょうか?
ご存知のとおり、JavaScript では関数をコンストラクターとして使用するとオブジェクトを作成できます。上記のコードは簡単に次のように記述できます。
function MyClass(param) {
this.param = param;
this.func1 = function (..) {
...
};
}
var myObj = new MyClass(param);
myObj.func1();
実際、非常にシンプルで理解するのは難しくありません。ただし、大規模な Javascript クラス ライブラリを構築する場合、大量のコードからどれがクラスで、どれが関数で、どれがクラス属性であるかを見つけるのは面倒です。
もちろん、これはメリットとデメリットを比較するためのものではなく、新しいクラスがどのように実装されるかが知りたいだけです。
上記のコードで new MyClass() のようなステートメントを使用することは、MyClass が関数である必要があることを意味し、また、new Class が関数オブジェクトを返す必要があることを意味します。文字通りの意味から、関数の初期化がであることがわかります。 used as コンストラクターを使用するため、new Class から返される関数では、initialize を使用してオブジェクトを初期化する必要があります。この分析に基づいて、次のコードを導き出すことができます。
function Class(argu) {
return function() {
var init = argu['initialize'] function() {};コンストラクターの初期化は行わず、空の関数をデフォルトのコンストラクターとして使用します
for(var p in argu) {
this[p] = argu[p];
}
init.apply(this, argument); // の this を使用します。 current function to 関数の初期化の代わりに、元の this
}
}
上記のコードは十分厳密ではありませんが、問題を説明するには十分です。 init.apply(this, argument) という文に注意する必要があります。ここには変数への参照がいくつかありますが、これは元々はInitialize のデフォルトであり、現在は返される匿名関数の this に置き換えられています。 、そしてこの匿名関数 は、新しいクラスを通じて作成されたカスタム クラスのコンストラクターです。もう 1 つは引数で、匿名関数のパラメータを参照します。これは、上記の new MyClass(param) のパラメータです。
これの変換はちょっとめまぐるしいので、もっと簡単な方法はないでしょうか?以下のコードを見てください:
function Class(argu) {
var obj = argu['initialize'] || function() {};
for (var p in argu) {
prototype[p] = argu [p]; // ここではプロトタイプが使用されていることに注意してください。 // 引き続き文字を返します。
これで簡単なクラス機構の構築が完了しました。このメカニズムを通じて、クラス コンストラクター、メソッド、プロパティを作成できますが、これらは明らかにパブリックです。では、プライベート変数とメソッドを実装するにはどうすればよいでしょうか。
JavaScript クラスのプライベート変数はクロージャ メカニズムを通じて完了できることがわかっています。ただし、 new Class({...}) を使用して変換した後は、効果的なクロージャを形成するのが明らかに困難です。この問題を回避するにはどうすればよいでしょうか?
function Class(argu) {
var _ = argu['private'] {};
eval('var obj = ' + ( argu ['initialize'] || function() {}).toString());
if(p == 'initialize' || p == 'private')
続行;
if(typeof argu[p] == 'function')
eval('obj.prototype[p] = ' + argu[p].toString());
else
obj.prototype[p] = argu[p ] ;
}
return obj;
}
関数オブジェクトの toString() メソッドを通じて関数コードを抽出し、 eval メソッドを使用してコードを実行することで、効果的なクロージャ範囲を構築して、プライベートメカニズム。次のように適用できます:
var person = new Class({
private: {
身長: 160,
体重: 50
},
初期化: function(名前, 身長, 体重) {
this.name = 名前;
_.he height=身長 || _.height;
_.weight = 体重 || _.weight;
},
show: function() {
alert('Name:' + this.name + '/nheight:' + _.height + '/nweight:' + _.weight);
}
});
var my = new Person("Zh");
my.show();
見た目は良くありませんが、実際のアプリケーションでは、実際にはあまり役に立ちません。主に効率の面で、通常の実装に比べて約4倍の時間がかかります。大規模なクラス ライブラリの構築では、これは耐えられませんが、小規模なアプリケーションでは、次のコードを実装する方が簡単で簡単です:
function MyClass(param) {
var privateVar = ...;
this.param = param;
this.func = function() {
alert(privateVar);
};
}