高度な Web アプリケーションを作成するための js オブジェクト指向テクノロジ_js オブジェクト指向

WBOY
リリース: 2016-05-16 18:33:53
オリジナル
943 人が閲覧しました

JavaScript オブジェクトは辞書です
C または C# では、オブジェクトについて話すときは、クラスまたは構造体のインスタンスを意味します。オブジェクトは、インスタンス化されるテンプレート (つまり、クラス) に応じて、異なるプロパティとメソッドを持ちます。 JavaScript オブジェクトの場合はそうではありません。 JavaScript では、オブジェクトは単なる名前と値のペアのセットです。つまり、JavaScript オブジェクトを文字列キーを含む辞書と考えてください。使い慣れた「.」(ドット) 演算子または「[]」演算子を使用して、オブジェクトのプロパティを取得および設定できます。これは、辞書を使用する場合の通常の方法です。次のコード スニペット

コードをコピー コードは次のとおりです。

var userObject = new Object ();
userObject.lastLoginTime = new Date();
alert(userObject.lastLoginTime);

は次のコード スニペットとまったく同じです。
var userObject = {} // new Object() userObject["lastLoginTime" ] = new Date();
alert(userObject["lastLoginTime"]);


userObject の定義で直接 lastLoginTime プロパティを定義することもできます。以下に示すように:


コードをコピー コードは次のとおりです: var userObject = { “ lastLoginTime”: new Date() };
alert(userObject.lastLoginTime);


これは C# 3.0 オブジェクト初期化子と非常に似ていることに注意してください。また、Python に詳しい人は、2 番目と 3 番目のスニペットで userObject をインスタンス化することは、Python で辞書を指定することとまったく同じであることに気づくでしょう。唯一の違いは、JavaScript オブジェクト/辞書は Python 辞書のようなハッシュ可能なオブジェクトではなく、文字列キーのみを受け入れることです。
これらの例は、JavaScript オブジェクトが C または C# オブジェクトよりも順応性が高いことも示しています。事前に lastLoginTime プロパティを宣言する必要はありません。userObject にその名前のプロパティがない場合、プロパティは userObject に直接追加されます。 JavaScript オブジェクトが辞書であることを覚えていれば、これは驚くことではありません。結局のところ、私たちは常に新しいキーワード (およびそれぞれの値) を辞書に追加しています。
このようにして、オブジェクトのプロパティが得られます。オブジェクトメソッドについてはどうでしょうか?同様に、JavaScript は C/C# とは異なります。オブジェクト メソッドを理解するには、まず JavaScript 関数を詳しく見る必要があります。
JavaScript 関数は最高です
多くのプログラミング言語では、関数とオブジェクトは別のものとしてみなされることがよくあります。 JavaScript では、その区別があいまいです。JavaScript 関数は実際には、実行可能コードが関連付けられたオブジェクトです。通常の関数は次のように考えてください。



コードをコピー コードは次のとおりです。 関数func(x) {
alert(x);
}
func(“blah”);


これは、JavaScript での関数の通常の定義方法です。ただし、関数は次のように定義することもできます。匿名関数オブジェクトを作成し、それを変数 func


コピー コード コードは次のとおりです。 次のように Function コンストラクターを使用することもできます:


コードをコピーします


コードは次のとおりです:


var func = new Function(“x”, “alert(x);”);

コードをコピー

コードは次のとおりです:

function SayHi(x) {
alert(“こんにちは, “ x “!”);
}
sayHi.text = “Hello World!”
sayHi[“ text2”] = “Hello World... もう一度。”;
alert(sayHi[“text”]) // 「Hello World!」を表示します。
alert(sayHi.text2);

関数はオブジェクトとして変数に代入したり、パラメータとして他の関数に渡したり、他の関数の値として返したり、関数の属性として使用したりすることもできます。ストレージ用のオブジェクトや配列の要素など。図 1 はそのような例を示しています。
JavaScript の関数は最高です
コードをコピーします コードは次のとおりです:

/ / 変数に匿名関数を割り当てます
vargreet = function(x) {
alert(“Hello, “
”);
greet(“MSDN 読者”); > // 関数を引数として別の
function square(x) {
return x * x;
}
function operatedOn(num, func) {
return func(num) ) ;
}
// 256
alert(operateOn(16, square));
// 関数を戻り値として表示します
function makeIncrementer() {
return function (x) { return x 1; };
var inc = makeIncrementer();
// として保存された 8 つの
alert(inc(7));配列要素
var arr = [];
arr[0] = function(x) { return x * x }; arr[2 ] = arr[0](arr[1]);
arr[3] = arr[0](arr[2]);
// 256
alert(arr[3]) を表示します]);
// オブジェクトのプロパティとして関数
var obj = { “toString” : function() { return "これはオブジェクトです。" } };
alert(obj);


これを念頭に置くと、オブジェクトにメソッドを追加するのは簡単になります。名前を選択して、その名前に関数を割り当てるだけです。したがって、対応するメソッド名に匿名関数を割り当てて、オブジェクト内に 3 つのメソッドを定義しました。
Code



Copy Code

コードは次のとおりです。 var myDog = { “name” : “Spot”, “bark” : function() {alert(“Woof!”) }; "displayFullName" : function() {
alert(this.name "The Alpha Dog");
},
"chaseMrPostman" : function() {
// を超える実装この記事の範囲
}
};
myDog.displayFullName();
myDog.bark(); // うわー! displayFullName 関数で使用される "this" キーワードについてよく理解してください。これは、メソッドが呼び出されるオブジェクトを指します (Visual Basic を使用する開発者もよく知っているはずです。"Me" と呼ばれます)。したがって、上の例では、displayFullName の "this" の値は myDog オブジェクトです。ただし、「this」の値は静的ではありません。 「this」が別のオブジェクトから呼び出される場合、図 2 に示すように、その値は対応するオブジェクトを指すように変更されます。
オブジェクトが変化すると「これ」も変化します




コードをコピー

コードは次のとおりです:

var markTwain = {
" rememberQuote": "ゴルフは甘やかされて歩くのに最適です。",
"sayIt" : displayQuote
};
var oscarWilde = {
"memorableQuote": "本当の友達があなたを正面から刺します。"
// 関数 displayQuote
// を oscarWilde のメソッドとして割り当てることなく、
//"sayIt" : displayQuote
}; >williamShakespeare.sayIt(); // true、true
markTwain.sayIt() // 彼はどこでゴルフをすればいいのかわかりませんでした
// これを見てください、各関数には call() があります
// これにより、関数を
// 引数として call() に渡されるオブジェクトのメソッドとして呼び出すことができます。
// 以下の行は、
を割り当てることと同等です。 // displayQuote を SayIt に渡し、oscarWilde.sayIt() を呼び出します。


図 2 の最後の行は、関数をオブジェクトのメソッドとして呼び出す別の方法を表しています。 JavaScript の関数はオブジェクトであることに注意してください。すべての関数オブジェクトには、最初の引数として関数を呼び出す call というメソッドがあります。つまり、関数の最初のパラメータとして call に渡されたオブジェクトは、関数呼び出しの「this」の値になります。この手法は、基本クラスのコンストラクターを呼び出すのに役立ちます。これについては後で説明します。
覚えておくべきことの 1 つは、「this」を含む (ただしオブジェクトを所有していない) 関数を決して呼び出さないことです。そうしないと、この呼び出しでは「this」がグローバル オブジェクトを参照するため、グローバル名前空間に違反することになり、必然的にアプリケーションに大惨事が発生することになります。たとえば、次のスクリプトは JavaScript のグローバル関数 isNaN の動作を変更します。こんなことはしないでください!
コード
コードをコピー コードは次のとおりです。

alert("NaN はNaN: " isNaN(NaN));
function x() {
this.isNaN = function() {
return “もうだめ!”;
};
}
// 警告 !!! グローバル オブジェクトを踏みにじっています !!!
x();
alert(“NaN は NaN: “ isNaN(NaN));オブジェクトのプロパティとメソッドを含むオブジェクトの作成方法を紹介しました。しかし、上記のすべてのコード スニペットに注意を払うと、プロパティとメソッドがオブジェクト定義自体にハードコーディングされていることがわかります。しかし、オブジェクトの作成をより詳細に制御する必要がある場合はどうすればよいでしょうか?たとえば、特定のパラメータに基づいてオブジェクトのプロパティ値を計算する必要がある場合があります。あるいは、オブジェクトのプロパティを実行時にのみ使用できる値に初期化する必要がある場合があります。オブジェクトの複数のインスタンスを作成する必要がある場合もあります (この要件は非常に一般的です)。
C# では、クラスを使用してオブジェクト インスタンスをインスタンス化します。ただし、JavaScript にはクラスがないため異なります。次のセクションで説明するように、この状況を利用できます。関数は、「new」演算子とともに使用するとコンストラクターとして機能します。
クラスではなくコンストラクター
前述したように、JavaScript OOP で最も奇妙な点は、C# や C とは異なり、JavaScript にはクラスがないことです。 C# で次のようなことを行うと、
Dog Spot = new Dog();
は Dog クラスのインスタンスであるオブジェクトを返します。しかし、JavaScript にはクラスがありません。クラスにアクセスする最も近い方法は、次のようにコンストラクターを定義することです:
コード



コードをコピー コードは次のとおりです。 : function DogConstructor(name) {
this.name = name;
this.respondTo = function(name) {
if(this.name == name) {
alert("ワンワン");
}
}
var Spot = new DogConstructor("スポット"); / いや、
spot.respondTo(“スポット”); // そう!


それで、結果はどうなるでしょうか?ここでは DogConstructor 関数の定義を無視して、次の行を見てください:
var Spot = new DogConstructor("Spot");
「new」演算子によって実行される操作は簡単です。まず、新しい空のオブジェクトを作成します。その後、その直後の関数呼び出しが実行され、新しい空のオブジェクトがその関数の "this" の値に設定されます。つまり、「new」演算子を含む上記のコード行は、次の 2 行のコードと同等であると考えることができます:



Copy code
コードは次のとおりです: // 空のオブジェクトを作成します var Spot = {}; // 空のオブジェクトのメソッドとして関数を呼び出します
DogConstructor.call (spot, "Spot");


DogConstructor 本体で見られるように、この関数を呼び出すとオブジェクトが初期化され、キーワード「this」は実行中にこのオブジェクトを参照します。電話。このようにして、オブジェクトのテンプレートを作成できます。同様のオブジェクトを作成する必要がある場合は、コンストラクターを使用して「new」を呼び出すことができます。返される結果は、完全に初期化されたオブジェクトになります。これは授業とよく似ていますね。実際、JavaScript のコンストラクターの名前は通常、シミュレートされるクラスの名前であるため、上記の例では、コンストラクター Dog に直接名前を付けることができます:
Code



コードをコピー
コードは次のとおりです: // これを class Dog と考えてください function Dog(name) { / / インスタンス変数
this.name = name;
// うーん...
this.respondTo = function(name) {
if(this.name == name) {
alert( "ワン");
}
}
var スポット = 新しい犬 ("スポット");
上記の Dog の定義では、name という名前のインスタンス変数を定義しました。 Dog をコンストラクターとして使用して作成された各オブジェクトには、インスタンス変数名の独自のコピーがあります (前述したように、これはオブジェクト ディクショナリ エントリです)。これは望ましい結果です。結局のところ、各オブジェクトには、その状態を表すためにインスタンス変数の独自のコピーが必要です。しかし、次の行を見ると、各 Dog インスタンスにも独自の ReplyTo メソッドのコピーがあることがわかります。これは無駄です。Dog インスタンス間で共有できる ReplyTo インスタンスは 1 つだけ必要です。この問題は、次のように Dog の外部でresponseToを定義することで回避できます:
コードをコピー コードは次のとおりです:

function ReplyTo() {
// ReplyTo 定義
}
function Dog(name) {
this.name = name;
// この関数をオブジェクトのメソッド
this.respondTo = ReplyTo;
}

このようにして、すべての Dog インスタンス (つまり、コンストラクター Dog で作成されたすべてのインスタンス) は、応答Toメソッド。しかし、メソッドの数が増えると、メンテナンスがますます難しくなります。最後に、コード ベースには多数のグローバル関数が存在し、さらに「クラス」を追加すると状況はさらに悪化します (特に、クラスのメソッドの名前が似ている場合)。ただし、この問題はプロトタイプ オブジェクトを使用するとより適切に解決できます。これについては次のセクションで説明します。
プロトタイプ
JavaScript を使用したオブジェクト指向プログラミングでは、プロトタイプ オブジェクトは中心的な概念です。この名前は、JavaScript のオブジェクトが既存のインスタンス (つまり、プロトタイプ) オブジェクトのコピーとして作成されるという概念に由来しています。このプロトタイプ オブジェクトのプロパティとメソッドは、プロトタイプのコンストラクターから作成されたオブジェクトのプロパティとメソッドとして表示されます。これらのオブジェクトは、プロトタイプからプロパティとメソッドを継承していると言えます。次のように新しい Dog オブジェクトを作成すると、
var buddy = new Dog("Buddy");
buddy によって参照されるオブジェクトは、この行からのみ可能ですが、そのプロトタイプからプロパティとメソッドを継承します。プロトタイプがどこから来たのかを正確に伝えることは不可能です。オブジェクト buddy のプロトタイプは、コンストラクター (この場合は関数 Dog) のプロパティから取得されます。
JavaScript では、すべての関数に、プロトタイプ オブジェクトを参照するために使用される「プロトタイプ」と呼ばれるプロパティがあります。このプロトタイプ オブジェクトには、関数自体を参照する「コンストラクター」と呼ばれるプロパティがあります。これは循環参照であり、図 3 はこの循環関係をよりよく示しています。

図 3 各関数のプロトタイプには Constructor 属性があります
「new」演算子を使用して関数を含むオブジェクト (上の例では Dog) を作成すると、結果のオブジェクトは Dog.prototype のプロパティを継承します。 図 3 では、Dog.prototype オブジェクトに Dog 関数を参照するコンストラクター プロパティがあることがわかります。このようにして、すべての Dog オブジェクト (Dog.prototype から継承) は、Dog 関数を参照するコンストラクター プロパティを持ちます。 図 4 のコード はこれを確認しています。 図 5 は、コンストラクター、プロトタイプ オブジェクト、およびそれらを使用して作成されたオブジェクトの間の関係を示しています。
コードをコピー コードは次のとおりです。

var Spot = new Dog("Spot" );
// Dog.prototype はスポットのプロトタイプです
alert(Dog.prototype.isPrototypeOf(spot));
// スポットはコンストラクター プロパティ
// を Dog.prototype
alert (spot.constructor == Dog.prototype.constructor);
alert(spot.constructor == Dog);
// ただし、コンストラクターのプロパティは
// に属しません。下の行は "false" を表示します
alert(spot.hasOwnProperty("constructor"));
// コンストラクターのプロパティは Dog.prototype に属します
// 下の行は "true" を表示します
alert (Dog.prototype.hasOwnProperty(“コンストラクター”));

図 5 インスタンスはプロトタイプを継承
読者の中には、図 4 の hasOwnProperty メソッドと isPrototypeOf メソッドの呼び出しに気づいた人もいるかもしれません。これらの手法はどこから来たのでしょうか?これらは Dog.prototype のものではありません。実際、Dog.prototype および Dog インスタンスには、toString、toLocaleString、および valueOf と呼ばれる他のメソッドがありますが、それらはいずれも Dog.prototype からのものではありません。 .NET Framework の System.Object がすべてのクラスの最終的な基本クラスとして機能するのと同じように、JavaScript の Object.prototype はすべてのプロトタイプの最終的な基本プロトタイプです。 (Object.prototype のプロトタイプは null です。)
この例では、Dog.prototype がオブジェクトであることに注意してください。これは、Object コンストラクター (非表示ですが) を呼び出すことによって作成されます。
Dog.prototype = new Object();


したがって、Dog インスタンスは Dog.prototype を継承します。 Object.prototype から継承します。これにより、すべての Dog インスタンスも Object.prototype のメソッドとプロパティを継承します。
すべての JavaScript オブジェクトはプロトタイプ チェーンを継承し、すべてのプロトタイプは Object.prototype で終了します。これまでに確認した継承はアクティブなオブジェクト間で行われることに注意してください。これは、宣言時のクラス間の継承を指す一般的な継承の概念とは異なります。したがって、JavaScript の継承はより動的になります。これは、次のような単純なアルゴリズムを使用して行われます。 オブジェクトのプロパティ/メソッドにアクセスしようとすると、JavaScript はそのオブジェクトにプロパティ/メソッドが定義されているかどうかを確認します。そうでない場合は、オブジェクトのプロトタイプがチェックされます。そうでない場合は、オブジェクトのプロトタイプのプロトタイプがチェックされ、Object.prototype に至るまで同様にチェックされます。図 6 は、この解析プロセスを示しています。

図 6 プロトタイプ チェーン内の toString() メソッドの解析 (画像をクリックすると拡大表示されます)
JavaScript がプロパティ アクセスとメソッド呼び出しを動的に解析する方法により、いくつかの特殊効果が生じます。
プロトタイプへの変更は、プロトタイプ オブジェクトを継承するオブジェクトの作成後であっても、そのオブジェクトに即座に反映されます。
プロパティ/メソッド X がオブジェクトに定義されている場合、同じ名前のプロパティ/メソッドはオブジェクトのプロトタイプに隠されます。たとえば、Dog.prototype で toString メソッドを定義することで、Object.prototype の toString メソッドをオーバーライドできます。
変更はプロトタイプから派生オブジェクトへの一方向にのみ伝播され、逆方向には伝播されません。
図 7 はこれらの効果を示しています。図 7 は、以前に発生した不要なメソッド インスタンスの問題を解決する方法も示しています。プロトタイプ内にメソッドを配置すると、オブジェクトごとに個別の関数オブジェクト インスタンスを持たなくても、オブジェクト間でメソッドを共有できるようになります。この例では、スポットで toString メソッドが何らかの方法でオーバーライドされるまで、ローバーとスポットは getBreed メソッドを共有します。その後、スポットは独自のバージョンの getBreed メソッドを持ちますが、新しい GreatDane で作成されたローバー オブジェクトと後続のオブジェクトは引き続き、GreatDane.prototype オブジェクトで定義された getBreed メソッドのインスタンスを共有します。
プロトタイプを継承
コードをコピー コードは次のとおりです:

function GreatDane() { }
var rover = new GreatDane();
var Spot = new GreatDane();
GreatDane.prototype.getBreed = function() {
return “グレートデーン” ”;
};
// この時点では、ローバーとスポットはすでに作成されていますが、
alert(rover.getBreed()); getBreed() in GreatDane.prototype
spot.getBreed = function() {
return "リトル グレートデーン"
};しかしもちろん、getBreed
// への変更は GreatDane.prototype
// およびそれを継承する他のオブジェクトには反映されません。
// スポット オブジェクトでのみ発生します
alert (rover.getBreed());



静的プロパティとメソッド
場合によっては、インスタンスではなくクラスのプロパティまたはメソッドにバインドする必要があります。 、静的プロパティとメソッド。関数は必要に応じてプロパティとメソッドを設定できるオブジェクトであるため、これは JavaScript で簡単に実行できます。コンストラクターは JavaScript のクラスを表すため、次のようにコンストラクター内で静的メソッドとプロパティを設定することで、クラスに直接追加できます。


Copy Code
コードは次のとおりです。 function DateTime() { } // 静的メソッド now() を設定します
DateTime.now = function() {
新しい日付を返します();
アラート(DateTime.now());
JavaScript で静的メソッドを呼び出すための構文は、C# の構文とほぼ同じです。コンストラクターの名前は実際にはクラスの名前であるため、これは驚くべきことではありません。このように、クラス、パブリック プロパティ/メソッド、静的プロパティ/メソッドがあります。他に何か必要ですか? もちろんプライベート会員も。ただし、JavaScript はプライベート メンバー (同様に保護されたメンバー) をネイティブにサポートしません。誰でもオブジェクトのすべてのプロパティとメソッドにアクセスできます。ただし、クラスにプライベート メンバーを含める方法はありますが、その前に、まずクロージャについて理解する必要があります。

おわりに
私は意識的に JavaScript を学んだことがありません。これがないと、実際の作業で AJAX アプリケーションを作成する準備が整わないことがわかったので、急いで学習する必要がありました。最初は自分のプログラミングレベルが数段階下がったように感じました。 (JavaScript! C の友人は何と言うでしょうか?) しかし、最初のハードルを乗り越えると、JavaScript は実際には強力で、表現力豊かで、非常に簡潔な言語であることがわかりました。他の一般的な言語がサポートし始めたばかりの機能も備えています。
JavaScript のより高度な機能の 1 つはクロージャのサポートです。この機能は、C# 2.0 が匿名メソッドを通じてサポートしています。クロージャは、内部関数 (または C# の内部匿名メソッド) がその外部関数のローカル変数にバインドされるときに発生する実行時現象です。明らかに、この内部関数が何らかの方法で外部関数にアクセスできない限り、あまり意味がありません。この点を例で説明すると分かりやすくなります。
単純な条件に基づいて一連の数値をフィルタリングする必要があるとします。この条件は、100 より大きい数値のみがフィルタを通過でき、残りの数値は無視されます。これを行うには、図 8 のような関数を作成します。
述語に基づいて要素をフィルタリングします
コードをコピーします コードは次のとおりです:

function filter(pred, arr) {
var len = arr.length;
var filtered = []; // new Array() の短縮版
// すべてを反復処理します。配列内の要素 ...
for(var i = 0; i < len; i ) {
var val = arr[i]
// 要素が述語を満たす場合、それを通過させます。
if (pred(val)) {
filtered.push(val);
}
}
フィルタリングされた戻り値;
}
var someRandomNumbers = [12, 32, 1, 3, 2, 2, 234, 236, 632,7, 8];
varnumberGreaterThan100 = filter(
function(x) { return (x > 100) ? true : false; },
someRandomNumbers) ;
// 234、236、632 を表示します
alert(numbersGreaterThan100);

ただし、今回は数値のみであると仮定して、別のフィルター条件を作成します。 300 を超える場合は、次の関数を作成できます。

コードをコピー コードは次のとおりです。 :

var greatThan300 = filter(
function(x) { return (x > 300) ? true : false; },
someRandomNumbers); 🎜>その後、50、25、10、600 などをフィルタリングする必要があるかもしれませんが、賢い人であれば、それらはすべて同じ述語「より大きい」を持ち、数値が異なるだけであることがわかるでしょう。したがって、次のような関数を使用して個々の数値を分離できます:


コードをコピーします コードは次のとおりです: function makeGreaterThanPredicate( lowerBound) {
return function(numberToCheck) {
return (numberToCheck > lowerBound)
}

このようにして、次のコードを書くことができます:

コード



コードをコピー
コード var greatThan10 = makeGreaterThanPredicate(10); alert(filter(greaterThan10, someRandomNumbers)); filter(greaterThan100, someRandomNumbers));

関数 makeGreaterThanPredicate によって返される内部匿名関数を観察すると、匿名内部関数が makeGreaterThanPredicate に渡されるパラメーターである lowerBound を使用していることがわかります。スコープの一般的な規則に従って、makeGreaterThanPredicate が終了すると、 lowerBound はスコープ外になります。ただし、ここでは、makeGreaterThanPredicate が終了した後も、内部の匿名関数は依然として lowerBound を保持します。これはクロージャと呼ばれるものです。内部関数は、それが定義されている環境 (つまり、外部関数のパラメータとローカル変数) を閉じるためです。
最初はクロージャがそれほど強力であるとは感じないかもしれません。しかし、正しく適用すると、アイデアをコードに変換するのに役立つ、非常に創造的で楽しい方法になります。 JavaScript におけるクロージャの最も興味深い使用法の 1 つは、クラスのプライベート変数をシミュレートすることです。

プライベート プロパティのシミュレーション
次に、クロージャがプライベート メンバーのシミュレーションにどのように役立つかを見てみましょう。通常、関数内のローカル変数には関数の外部からアクセスできません。関数が終了すると、ローカル変数はさまざまな実際的な理由から永久に消えます。ただし、ローカル変数が内部関数のクロージャによってキャプチャされた場合、ローカル変数は存続します。この事実は、JavaScript のプライベート プロパティをエミュレートするための鍵となります。 Person クラスがあるとします。
Code
Copy code コードは次のとおりです:

関数 人 (名前, 年齢) {
this.getName = function() { return name };
this.setName = function(newName) { name = newName }; = function() { return age; };
this.setAge = function(newAge) { age = newAge };


パラメータ名と年齢は、コンストラクターの人物。人物が戻ってきたら、名前と年齢は永久に消えるはずです。ただし、これらは Person インスタンスのメソッドとして割り当てられた 4 つの内部関数によってキャプチャされるため、名前と年齢は事実上存続し続けますが、厳密にはこれら 4 つのメソッドを介してのみアクセスできます。

コード


コードをコピーします コードは次のとおりです:
var ray = 新しい人物("レイ", 31);
alert(ray.getName());
alert(ray.getAge()); Ray”);
// 瞬時に若返ります!
ray.setAge(22);
alert(ray.getName() " は " ray.getAge()
" 歳です。") ;


コンストラクターで初期化されていないプライベート メンバーは、次のようにコンストラクターのローカル変数になることができます:



コードをコピーします。
コードは次のとおりです。 function person(name, age) { var 職業; this.getjob = function() { 職業を返す; };
this.setSoup = function(newOcc) { 職業 =
newOcc }// 名前と年齢のアクセサー


これらはプライベート メンバーであり、C# から期待されるプライベート メンバーとは若干異なることに注意してください。 C# では、クラスのパブリック メソッドはそのプライベート メンバーにアクセスできます。しかし、JavaScript では、プライベート メンバーには、クロージャ内でプライベート メンバーを所有するメソッドを通じてのみアクセスできます (これらのメソッドは通常のパブリック メソッドとは異なるため、特権メソッドと呼ばれることがよくあります)。したがって、Person のパブリック メソッドでは、プライベート メンバーの特権アクセサー メソッドを介してプライベート メンバーにアクセスする必要があります:




コードをコピー


コードは次のとおりです。 ;
Douglas Crockford は、プライベート メンバーをシミュレートするためにクロージャーを使用する手法を最初に発見した (またはおそらく公開した) 人として有名です。彼の Web サイト javascript.crockford.com には、JavaScript に関する豊富な情報が含まれており、JavaScript に興味のある開発者は必ず読む必要があります。

クラスからの継承
ここまで、コンストラクターとプロトタイプ オブジェクトを使用して JavaScript でクラスを模擬できる方法を見てきました。プロトタイプ チェーンによって、すべてのオブジェクトが Object.prototype のパブリック メソッドを持つようになり、クラスのプライベート メンバーをシミュレートするためにクロージャを使用する方法がわかりました。しかし、ここには何かが欠けています。 C# では毎日行うことですが、クラスから派生する方法をまだ見ていません。残念ながら、JavaScript でクラスから継承することは、C# でコロンを入力して継承するほど簡単ではなく、より多くの作業が必要になります。一方、JavaScript は非常に柔軟で、さまざまな方法でクラスを継承できます。
たとえば、図 9 に示すように、基本クラス Pet があり、これには派生クラス Dog があります。これを JavaScript で実装するにはどうすればよいでしょうか?ペットクラスは簡単です。実装方法は確認しました:

コードをコピーします コードは次のとおりです:

// class Pet
function Pet(name) {
this.getName = function() { return name }; ; };
}
Pet.prototype.toString = function() {
return "このペットの名前は次のとおりです。
}; Pet
var parrotty = new Pet(“Parrotty the Parrot”);
alert(parrotty); さて、Pet から派生したクラス Dog を作成するにはどうすればよいでしょうか。図 9 からわかるように、Dog には別のプロパティ Breeze があり、Pet の toString メソッドをオーバーライドします (JavaScript の規約では、C# で推奨されている Pascal ケーシングではなく、メソッド名とプロパティ名にキャメル ケーシングを使用することに注意してください)。図 10 は、これを行う方法を示しています。

Pet クラスからの派生



コードをコピーします
コードは次のとおりです: // class Dog : Pet // public Dog(string name, string Brede) function Dog(name, Breeze) {
// think Dog : Base(name)
Pet .call(this, name);
this.getBreed = function() { return Breed; };
// 読み取り専用です。 function(newBreed) { name = newName; };
}
// これにより、Dog.prototype は Pet.prototype
Dog.prototype = new Pet() から継承されます。 // Pet .prototype.constructor
// が Pet を指すことを覚えておいてください。Dog インスタンスの
// コンストラクターが Dog を指すようにします。 / 次に、Pet .prototype.toString
Dog.prototype.toString = function() {
return 「この犬の名前は「 this.getName()
」、その品種は「 this 」をオーバーライドします。 .getBreed();
};
// クラス Dog
var Dog = new Dog(“Buddy”, “Great Dane”); // 新しい toString() をテストします。 🎜>alert(dog );
//instanceof のテスト (is 演算子と同様)
// (dog は Dog)? はい
alert(dog instanceof Dog);ペットです)? はい
alert(犬インスタンスオブペット);
// (犬はオブジェクトです)? はい
アラート(犬インスタンスオブオブジェクト);


プロトタイプを使用しますテクニックが正しく設定されている プロトタイプ チェーンが含まれているため、C# を使用している場合、テストされたインスタンスは期待どおりに実行されます。また、特権メソッドは引き続き期待どおりに機能します。

モック名前空間
C および C# では、名前空間は名前の競合を最小限に抑えるために使用されます。たとえば、.NET Framework では、名前空間は Microsoft.Build.Task.Message クラスと System.Messaging.Message を区別するのに役立ちます。 JavaScript には名前空間をサポートする言語固有の機能はありませんが、オブジェクトを使用して名前空間をエミュレートするのは簡単です。 JavaScript ライブラリを作成する場合は、次のように、グローバル関数やクラスを定義せずに名前空間内でラップできます。




コードをコピー


コードは次のとおりです:


var MSDNMagNS = {};
MSDNMagNS.Pet = function(name) { // ここにコードを記述します }; toString = function() { // code };
var pet = new MSDNMagNS.Pet("Yammer");
名前空間のレベルは一意ではない可能性があります。ネストされた名前空間が作成されました: コード
コードをコピー


コードは次のとおりです:

var MSDNMagNS = {};
// ネストされた名前空間「Examples」
MSDNMagNS.Examples = {};
MSDNMagNS.Examples.Pet = function(name) { // コード } ;
MSDNMagNS.Examples.Pet.prototype.toString = function() { // コード };
var pet = new MSDNMagNS.Examples.Pet(“Yammer”);ご想像のとおり、このような長くネストされた名前空間を入力するのは面倒な作業です。 幸いなことに、ライブラリ ユーザーは名前空間の短いエイリアスを簡単に指定できます:


コードをコピーします コードは次のとおりです: // MSDNMagNS.Examples と Pet 定義...
// 「Eg = MSDNMagNS.Examples; を使用する」と考えてください。
var Eg = MSDNMagNS.Examples; (“Yammer”);
alert(pet);


Microsoft AJAX ライブラリのソース コードを見ると、ライブラリの作成者が同様の手法を使用していることがわかります。名前空間を実装します (静的メソッド Type.registerNamespace の実装を参照)。詳細については、サイドバー「OOP と ASP.NET AJAX」を参照してください。

これが JavaScript の記述方法でしょうか?
JavaScript がオブジェクト指向プログラミングを非常によくサポートしていることがわかりました。これはプロトタイプベースの言語ですが、他の一般的な言語で一般的なクラスベースのプログラミング スタイルに対応できる柔軟性とパワーを備えています。しかし問題は、JavaScript コードをこのように記述すべきかということです。 JavaScript でプログラミングする方法は、C# または C でコーディングする方法と同じである必要がありますか? JavaScript にはない機能をエミュレートする、より賢い方法はあるでしょうか?すべてのプログラミング言語は異なり、ある言語にとって最適なものが、別の言語にとって最適であるとは限りません。
JavaScript では、(クラスを継承するクラスとは異なり) オブジェクトがオブジェクトを継承するのを見てきました。したがって、静的継承階層を使用して多くのクラスを構築することは、JavaScript には適さない可能性があります。おそらく、Douglas Crockford が記事「JavaScript におけるプロトタイプの継承」で述べたように、JavaScript でプログラミングする方法は、プロトタイプ オブジェクトを作成し、次の単純なオブジェクト関数を使用して、元のオブジェクトを継承する新しいオブジェクトを作成することです。 >


コードをコピー

コードは次のとおりです。 function object(o) { function F() { } F.prototype = o; return new F();
}


その後、JavaScript のオブジェクトは簡単に作成できます。必要に応じて、オブジェクトに新しいフィールドと新しいメソッドを追加します。
これは確かに素晴らしいことですが、世界中のほとんどの開発者がクラスベースのプログラミングに精通していることは否定できません。実際、ここでもクラスベースプログラミングが登場します。 JavaScript 2.0 には、ECMA-262 仕様の次期バージョン 4 に従って実際のクラスが含まれます (ECMA-262 は JavaScript の公式仕様です)。その結果、JavaScript はクラスベースの言語に進化しています。ただし、JavaScript 2.0 が広く使用されるようになるまでには数年かかるでしょう。同時に、現在の JavaScript はプロトタイプベースのスタイルとクラスベースのスタイルで JavaScript コードを完全に読み書きできることも明確にする必要があります。

今後の展望
インタラクティブなシック クライアント AJAX アプリケーションの普及により、JavaScript は .NET 開発者にとって最も重要なツールの 1 つになりつつあります。ただし、C、C#、Visual Basic などの言語に慣れている開発者は、そのプロトタイプの性質に最初は驚くかもしれません。 JavaScript を学習した経験は、多少の不満はありましたが、豊かな経験であったことがわかりました。この記事があなたの経験を少しでもスムーズにしてくれれば幸いです。それがまさに私が目指していることだからです。
関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート