導入
この記事では、ECMAScriptのオブジェクト指向プログラミングのさまざまな側面を検討します(ただし、このトピックは以前に多くの記事で説明されています)。これらの問題を理論的な観点から見てみましょう。特に、オブジェクトの作成アルゴリズム、オブジェクト間の関係(基本的な関係 - 継承を含む)も議論で利用できるかを検討します(JavaScriptのOOPの概念的な曖昧さの一部が削除されることを願っています)。
元の英語のテキスト:http://dmitrysoshnikov.com/ecmascript/chapter-7-1-oop-general-theory/
はじめに、パラダイムと思考
ECMAScriptでOOPテクニカル分析を実施する前に、OOPのいくつかの基本的な特性を習得し、紹介の主要な概念を明確にする必要があります。
ECMAScriptは、構造化されたオブジェクト指向、機能的、命令などを含むさまざまなプログラミング方法をサポートしており、場合によってはアスペクト指向のプログラミングもサポートしています。しかし、この記事では、オブジェクト指向のプログラミングについて説明しているため、ECMAScriptのオブジェクト指向プログラミングの定義を説明します。
ECMAScriptは、プロトタイプの実装に基づいたオブジェクト指向のプログラミング言語です。
プロトタイプベースのOOPと静的クラスベースの方法には多くの違いがあります。彼らの直接の詳細な違いを見てみましょう。
クラスベースおよびプロトタイプベース
前の文の重要なポイントはすでに指摘されていることに注意してください - それは完全に静的クラスに基づいています。 「静的」という単語では、強く入力された静的オブジェクトと静的クラスを理解しています(必須ではありませんが)。
この状況に関して、多くのフォーラム文書は、これがJavaScriptの「クラスとプロトタイプ」を比較することに反対する主な理由であることを強調しています。それらの実装の違い(動的クラスに基づくPythonやRubyなど)はポイントにそれほど反対していませんが(いくつかの条件が書かれていますが、アイデアにはいくつかの違いがありますが、JavaScriptはそれほど代替ではありません)が、反対は静的クラスと動的プロトタイプです(Statics +クラス対ダイナミクス +プロトタイプ)。正確には、静的クラス(C ++、Javaなど)とその従属およびメソッド定義メカニズムにより、ITとプロトタイプの実装の正確な違いを確認できます。
しかし、それらを1つずつリストしましょう。これらのパラダイムの一般的な原則と主な概念を考えてみましょう。
静的クラスに基づいています
クラスベースのモデルには、クラスとインスタンスに関する概念があります。クラスのインスタンスは、多くの場合、オブジェクトまたはパラダイムという名前も付いています。
クラスとオブジェクト
クラスは、インスタンス(つまりオブジェクト)の抽象化を表します。これは数学に少し似ていますが、タイプまたは分類と呼びます。
たとえば(ここの例以下は擬似コードです):
コードコピーは次のとおりです。
c = class {a、b、c} //機能a、b、cを含むクラスC
インスタンスの特性は、属性(オブジェクト説明)とメソッド(オブジェクトアクティビティ)です。特性自体もオブジェクトと見なすことができます。つまり、属性が書き込み可能で、構成可能で、設定可能(ゲッター/セッター)などです。したがって、オブジェクトは状態を保存します(つまり、クラスで説明されているすべての属性の特定の値)、クラスは、インスタンスの厳密に不変の構造(特性)および厳密に不変の行動(方法)を定義します。
コードコピーは次のとおりです。
c = class {a、b、c、method1、method2}
c1 = {a:10、b:20、c:30} //クラスcはインスタンスです:オブジェクトもっと
c2 = {a:50、b:60、c:70} //クラスcはインスタンスです:オブジェクトもっとも、独自の状態を持つ(つまり、属性値)
階層継承
コードの再利用を改善するために、クラスをあるものから別のものに拡張して、追加情報を追加できます。このメカニズムは(階層的)継承と呼ばれます。
コードコピーは次のとおりです。
d = classはc = {d、e} // {a、b、c、d、e}を拡張します
d1 = {a:10、b:20、c:30、d:40、e:50}
クラスのインスタンスでパーティーに電話するとき、ネイティブクラスは通常、この方法を探します。見つからない場合は、親クラスに移動して直接検索します。発見されていない場合は、親クラスの親クラスに移動して検索します(たとえば、厳密な相続チェーンで)。継承の最上部が見つかっていないことがわかった場合、結果は次のとおりです。オブジェクトには同様の動作がなく、結果を得ることができません。
コードコピーは次のとおりです。
d1.method1()// d.method1(no) - > c.method1(yes)
d1.method5()// d.method5(no) - > c.method5(no) - >結果はありません
サブクラスにコピーされていない継承方法と比較して、プロパティは常にサブクラスに複雑です。サブクラスDが親クラスC:属性A、B、Cから継承され、dの構造が{a、b、c、d、e}}であることがわかります。ただし、メソッド{method1、method2}は過去をコピーするのではなく、過去を継承します。したがって、非常に深いクラスにオブジェクトがまったく必要としないプロパティがある場合、サブクラスにはこれらのプロパティもあります。
クラスに基づく重要な概念
したがって、次の重要な概念があります。
1。オブジェクトを作成する前に、クラスを宣言する必要があります。まず、クラスを定義する必要があります。
2。したがって、オブジェクトは、独自の「絵文字と類似性」(構造と行動)に抽象化されたクラスから作成されます
3。この方法は、厳格で直接的で変化のない継承チェーンを介して処理されます。
4.サブクラスには、継承チェーン内のすべての属性が含まれています(一部の属性がサブクラスで必要とされていない場合でも)。
5.クラスインスタンスを作成します。クラスは(静的モデルのため)そのインスタンスの特性(属性または方法)を変更することはできません。
6.インスタンス(厳密な静的モデルのため)は、インスタンスに対応するクラスで宣言された動作と属性を除いて、追加の動作や属性を持つことはできません。
JavaScriptのOOPモデルを置き換える方法を見てみましょう。これは、プロトタイプベースのOOPであることをお勧めします。
プロトタイプに基づいています
ここでの基本概念は、動的な可変オブジェクトです。変換(値だけでなく機能も含む完全な変換)は、動的言語に直接関連しています。次のようなオブジェクトは、クラスなしですべてのプロパティ(プロパティ、メソッド)を個別に保存できます。
コードコピーは次のとおりです。
object = {a:10、b:20、c:30、method:fn};
object.a; // 10
object.c; // 30
object.method();
さらに、動的により、独自の機能を簡単に変更(追加、削除、変更)できます。
コードコピーは次のとおりです。
object.method5 = function(){...}; //新しいメソッドを追加します
object.d = 40; //新しい属性「D」を追加
object.cを削除します。 //属性を削除する「もっと」
object.a = 100; //属性を変更する "�"
//結果は次のとおりです。オブジェクト:{a:100、b:20、d:40、method:fn、method5:fn};
つまり、いくつかの機能が存在しない場合、それが作成され、割り当てが初期化され、存在する場合は更新されます。
この場合、コードの再利用はクラスを拡張することによって実装されていません(ここにクラスの概念がないためにクラスを変更できないとは言わなかったことに注意してください)が、プロトタイプによって実装されています。
プロトタイプは、他のオブジェクトのプリミティブコピーとして使用されるオブジェクトです。または、一部のオブジェクトに独自の必要な特性がない場合、プロトタイプはこれらのオブジェクトの代表として使用し、補助オブジェクトとして機能します。
委任に基づいています
オブジェクトは、実行時にプロトタイプのダイナミクスを簡単に変更できるため、任意のオブジェクトを別のオブジェクトのプロトタイプオブジェクトとして使用できます。
現在、具体的な実装ではなく紹介を検討していることに注意してください。ECMaScriptでの具体的な実装について議論すると、独自の特性の一部が表示されます。
例(pseudocode):
コードコピーは次のとおりです。
x = {a:10、b:20};
y = {a:40、c:50};
y。[[プロトタイプ]] = x; // xはyのプロトタイプです
ええ; // 40、独自の特性
YC; // 50、それはそれ自体の特徴でもあります
YB; // 20プロトタイプから取得:yb(no) - > y。[[プロトタイプ]]。b(yes):20
yaを削除します。 //独自の「�」を削除する
ええ; // 10プロトタイプから入手してください
z = {a:100、e:50}
y。[[プロトタイプ]] = z; // yのプロトタイプをzに変更します
ええ; // 100プロトタイプzから取得
ye // 50、プロトタイプzからも取得
ZQ = 200 //プロトタイプに新しい属性を追加する
yq //変更はyにも適用されます
この例は、自分の属性が必要なように、補助オブジェクト属性としてのプロトタイプの重要な機能とメカニズムを示しています。独自の属性と比較して、これらの属性はデリゲート属性です。このメカニズムはデリゲートと呼ばれ、それに基づくプロトタイプモデルは代表団のプロトタイプ(または代表団ベースのプロトタイプ)です。参照メカニズムは、オブジェクトに情報を送信すると呼ばれます。オブジェクトが応答を取得しない場合、それを見つけるためにプロトタイプに委任されます(メッセージに応答しようとする必要があります)。
この場合のコード再利用は、代表団ベースの継承またはプロトタイプベースの継承と呼ばれます。すべてのオブジェクトはプロトタイプと見なすことができるため、つまり、プロトタイプには独自のプロトタイプを持つこともできます。これらのプロトタイプは一緒に接続されており、いわゆるプロトタイプチェーンを形成します。チェーンは静的クラスでも階層的ですが、簡単に再配置され、階層や構造を変更することができます。
コードコピーは次のとおりです。
x = {a:10}
y = {b:20}
y。[[プロトタイプ]] = x
z = {c:30}
z。[[プロトタイプ]] = y
ZA // 10
//プロトタイプチェーンで見つかったZA:
// za(no) - >
// z。[[プロトタイプ]]。a(no) - >
// z。[[プロトタイプ]]。[[プロトタイプ]]。a(yes):10
オブジェクトとそのプロトタイプチェーンがメッセージ送信に応答できない場合、オブジェクトは対応するシステム信号をアクティブにすることができます。これは、プロトタイプチェーンの他の代表者が処理することができます。
このシステム信号は、動的クラスに基づくシステムを含む多くの実装で利用できます。 __getattr__でpython、__call in php; __NOSUCHMETHOD__ ECMAScriptなどでの実装。
例(SpidermonkeyのECMAScriptの実装):
コードコピーは次のとおりです。
var object = {
//メッセージに応答できないシステム信号をキャッチします
__NOSUCHMETHOD__:function(name、args){
アラート([name、args]);
if(name == 'test'){
return '.test()メソッドが処理されます';
}
DELEGATE [name] .apply(this、args)を返します。
}
};
var Delegate = {
正方形:関数(a){
a * aを返します。
}
};
アラート(object.square(10)); // 100
alert(object.test()); // .test()メソッドが処理されます
つまり、静的クラスの実装に基づいて、メッセージが応答できない場合、現在のオブジェクトには必要な特性がないが、プロトタイプチェーンから取得しようとすると、結果が得られるか、一連の変更後にオブジェクトがある場合があります。
ECMAScriptに関しては、特定の実装は次のとおりです。代表団ベースのプロトタイプを使用します。ただし、仕様と実装からわかるように、独自の特性もあります。
連結モデル
正直なところ、別の状況(できるだけ早くECMAScriptで使用されない)について何かを言う必要があります。この状況は、プロトタイプが他のオブジェクトからネイティブオブジェクトの元の置換に複雑である場合です。このケースでは、再利用は、オブジェクト作成段階での代表者ではなく、オブジェクトの実際のコピー(クローン)です。このプロトタイプは、連結プロトタイプと呼ばれます。オブジェクトのすべてのプロトタイプのプロパティをコピーすると、プロパティとメソッドをさらに完全に変更できます。プロトタイプとして、自分自身を変更することもできます(代表ベースのモデルでは、この変更は既存のオブジェクトの動作を変更しませんが、プロトタイプの特性を変更します)。この方法の利点は、スケジューリングと委任時間を短縮できることですが、不利な点はメモリを使用することです。
アヒルタイプ
静的なクラスベースのモデルと比較して、動的に弱いタイプの変更オブジェクトに戻ると、これらのことを行うことができるかどうか、およびオブジェクトが持っているタイプ(クラス)を確認する必要がありますが、それが対応するメッセージに関連することができるかどうか(つまり、チェック後に行う能力があるかどうか)。
例えば:
コードコピーは次のとおりです。
//静的ベースのモデルで
if(someclassのオブジェクトインスタンス){
//いくつかの動作が実行されています
}
//動的実装で
//現時点ではオブジェクトの種類が関係ありません
//変異、種類、および特性を自由に変更できるためです。
//重要なオブジェクトがテストメッセージに応答できるかどうか
if(isfunction(object.test))// ecmascript
object.respond_to?(:test)// rubyの場合
hasattr(object、 'test'):// pythonの場合
これはドックタイプと呼ばれます。つまり、オブジェクトは、階層内のオブジェクトの位置ではなく、チェック時に独自の特性によって識別できます。
プロトタイプに基づく重要な概念
この方法の主な機能を見てみましょう。
1.基本概念はオブジェクトです
2。オブジェクトは完全に動的で可変です(理論的には、あるタイプから別のタイプに完全に変換できます)
3。オブジェクトには、独自の構造と動作を説明する厳格なクラスがなく、オブジェクトにはクラスが必要ありません。
4。オブジェクトにはクラスクラスがありませんが、プロトタイプを持つことができます。メッセージに応答できない場合、プロトタイプに委任できます。
5。オブジェクトのプロトタイプは、ランタイム中にいつでも変更できます。
6。代表ベースのモデルでは、プロトタイプの特性を変更すると、プロトタイプに関連するすべてのオブジェクトに影響します。
7.連結プロトタイプモデルでは、プロトタイプは他のオブジェクトからクローン化された元のコピーであり、さらに完全に独立したコピーオリジナルになります。プロトタイプの特性の変換は、そこからクローン化されたオブジェクトに影響しません。
8。メッセージを応答できない場合、その発信者は追加の措置を講じることができます(例:スケジューリングを変更します)
9。オブジェクトの障害は、レベルと属するクラスではなく、現在の特性によって決定できます。
ただし、考慮すべき別のモデルもあります。
動的クラスに基づいています
上記の例に示されている「クラス対プロトタイプ」の違いは、この動的なクラスベースのモデルではそれほど重要ではないと考えています(特に、プロトタイプチェーンが変更されていない場合、より正確な区別のために静的クラスを考慮する必要があります)。例として、PythonまたはRuby(または他の同様の言語)でも使用できます。これらの言語はすべて、動的なクラスベースのパラダイムを使用します。ただし、いくつかの側面では、プロトタイプに基づいて実装されている特定の機能を確認できます。
次の例では、デリゲートのプロトタイプに基づいて、クラス(プロトタイプ)を増幅し、このクラスに関連するすべてのオブジェクトに影響を与えることができることがわかります。また、実行時にこのオブジェクトのクラスを動的に変更することもできます(デリゲートに新しいオブジェクトを提供)など。
コードコピーは次のとおりです。
#python
クラスA(オブジェクト):
def __init __(self、a):
self.a = a
def Square(self):
self.a * self.aを返します
a = a(10)#インスタンスを作成します
印刷(AA)#10
AB = 20#クラスに新しいプロパティを提供する
print(ab)#20「a」インスタンスでアクセスできます
a = 30#独自のプロパティを作成する
印刷(AB)#30
del AB#独自の属性を削除します
print(ab)#20-クラスから再び取得する(プロトタイプ)
#プロトタイプベースのモデルのように
#実行時にオブジェクトのプロトタイプを変更できます
クラスB(オブジェクト):#空のクラスb
合格
b = b()#bインスタンス
b .__ class__ = a#動的にクラス(プロトタイプ)を変更する
Ba = 10#新しい属性を作成します
print(b.square())#100-クラスAメソッドは現時点で利用できます
#削除されたクラスに参照を表示できます
del a
del b
#しかし、オブジェクトにはまだ暗黙の参照があり、これらのメソッドはまだ利用可能です
print(b.square())#100
#しかし、現時点ではクラスを変更することはできません
#これは実装の機能です
b .__ class__ = dict#エラー
Rubyの実装は似ています。完全に動的なクラスも使用します(ちなみに、Pythonの現在のバージョンではRubyおよびEcMascriptと比較して、クラス(プロトタイプ)を増幅することはできません)(またはクラス)の特性を完全に変更できます(クラスにメソッド/属性を追加すると、これらの変更は既存のオブジェクトに影響しますが、クラスを動的に変えることはできません。
ただし、この記事はPythonとRuby専用ではないため、あまり言わないので、ECMAScript自体について説明し続けましょう。
しかし、この前に、JavaScriptに関する以前の記事の多くがこれらの問題をカバーすることが多いため、いくつかのoopsにある「合成糖」を見る必要があります。
このセクションで注意する必要がある唯一の間違った文は、「JavaScriptはクラスではなく、プロトタイプを持ち、クラスを置き換えることができます。」すべてのクラスベースの実装が完全に異なるわけではないことを知る必要があります。 「JavaScriptは異なる」と言えますが、他の関連する機能があることを(「クラス」の概念以外に)考慮する必要もあります。
さまざまなOOP実装のその他の機能
このセクションでは、ECMAScriptのOOP実装など、コードの再利用に関する他の機能やさまざまなOOP実装を簡単に紹介します。その理由は、JavaScriptでのOOP実装の以前の外観には、習慣的な思考制限があるためです。唯一の主な要件は、技術的およびイデオロギー的に証明されるべきであることです。他のOOP実装で構文糖機能を発見していないと言えません。JavaScriptが純粋なOOP言語ではないことを知りません。
多型
ECMAScriptでは、オブジェクトが意味するいくつかの多型があります。
たとえば、ネイティブオブジェクトのプロパティと同様に、関数を異なるオブジェクトに適用できます(この値は、実行コンテキストに入るときに決定されるため):
コードコピーは次のとおりです。
function test(){
アラート([this.a、this.b]);
}
test.call({a:10、b:20}); // 10、20
test.call({a:100、b:200}); // 100、200
var a = 1;
var b = 2;
テスト(); // 1、2
ただし、例外があります。date.prototype.gettime()メソッドは、標準に従って、常に日付オブジェクトがある必要があります。そうしないと、例外がスローされます。
コードコピーは次のとおりです。
alert(date.prototype.getTime.call(new date())); // 時間
alert(date.prototype.getTime.call(new String( ''))); // typeRror
関数を定義する場合のいわゆるパラメーター多型は、すべてのデータ型と同等ですが、多型パラメーター(配列のソートソート方法とそのパラメーター - ポリ型のソート関数など)のみを受け入れます。ちなみに、上記の例はパラメーター多型と見なすこともできます。
プロトタイプのメソッドは空に定義でき、すべての作成されたオブジェクトはメソッド(つまり、「1つのインターフェイス(署名)、複数の実装」)を再定義(実装)する必要があります。
多型は、上記のアヒルのタイプに関連しています。つまり、オブジェクトのタイプと階層内のその位置はそれほど重要ではありませんが、必要なすべての機能を備えている場合は簡単に受け入れることができます(つまり、一般的なインターフェイスが重要であり、実装を変更できます)。
パッケージ
カプセル化についてはしばしば間違った見解があります。このセクションでは、OOP実装の構文糖、つまりよく知られている修飾子について説明します。この場合、oopの実装で便利な「砂糖」 - よく知られている修飾子:プライベート、保護、および公開(またはオブジェクトのアクセスレベルまたはアクセスモディファイア)について説明します。
ここでは、カプセル化の主な目的について思い出させたいと思います。カプセル化は、クラスに直接何かを書き込む隠された「悪意のあるハッカー」を選択するのではなく、抽象的な追加です。
これは大きな間違いです。隠すために隠されたものを使用してください。
プログラミングの利便性のために、アクセスレベル(プライベート、保護、およびパブリック)は、多くのオブジェクト指向(本当に非常に便利な構文糖)で実装されており、システムをより抽象的に説明および構築しています。
これらは、いくつかの実装(PythonやRubyなど)で見ることができます。一方で(Pythonで)、これらの__プライベート_を保護したプロパティ(アンダースコア名の仕様を介して)は、外部からアクセスできません。一方、Pythonは、特別なルール(_classname__field_name)から外部からアクセスできます。
コードコピーは次のとおりです。
クラスA(オブジェクト):
def __init __(self):
self.public = 10
self .__ private = 20
def get_private(self):
自己を返します。__プライベート
# 外:
a = a()#aの例
print(a.public)#ok、30
print(a.get_private())#ok、20
print(a .__プライベート)#は、でのみ利用できるため失敗しました
#しかし、Pythonでは、特別なルールにアクセスできます
print(a._a__private)#ok、20
Ruby:一方では、プライベートと保護された特性を定義する能力があり、他方では、カプセル化されたデータを取得するための特別な方法(instance_variable_get、instance_variable_set、sendなど)もあります。
コードコピーは次のとおりです。
クラスA
def initialize
@a = 10
終わり
def public_method
private_method(20)
終わり
プライベート
def private_method(b)
@a + bを返します
終わり
終わり
a = a.new#newインスタンス
A.public_method#ok、30
aa#failed、@a-はプライベートインスタンス変数です
#「private_method」はプライベートで、クラスAでのみアクセスできます
a.private_method#エラー
#しかし、データを取得できる特別なメタデータメソッド名があります
a.send(:private_method、20)#ok、30
a.instance_variable_get(:@a)#ok、10
主な理由は、プログラマーが取得したいカプセル化(「非表示」を使用していないことに注意してください)です。このデータが何らかの方法で誤って変更されている場合、またはエラーがある場合、全体の責任はプログラマーですが、単に「特定のフィールドを何気なく変更」しないでください。しかし、これが頻繁に発生する場合、それは通常、オブジェクトと「通話」するための一般的なAPIであるため、悪いプログラミングの習慣とスタイルです。
繰り返しますが、カプセル化の基本的な目的は、ハッカーがデータを隠すのを防ぐのではなく、補助データのユーザーから抽象化することです。より深刻なことに、カプセル化は、プライベートを使用してデータを変更してソフトウェアセキュリティの目的を達成することではありません。
ヘルパーオブジェクト(ローカル)のカプセル化では、最小限のコスト、ローカリゼーション、予測の変更を伴うパブリックインターフェイスの動作の変化の実現可能性を提供します。これは、まさにカプセル化の目的です。
さらに、セッター法の重要な目的は、複雑な計算を抽象化することです。たとえば、element.innerhtml setter -abstractステートメント - 「この要素内のHTMLは次のとおりです」と、innerHTML属性のセッター関数を計算して確認することは困難です。この場合、問題は主に抽象化を伴いますが、カプセル化が発生する可能性があります。
カプセル化の概念は、OOPに関連するだけではありません。たとえば、あらゆる種類の計算をカプセル化する単純な関数である可能性があり、抽象的です(たとえば、function math.round(......)の実装方法など、ユーザーに知らせる必要はありません。ユーザーは単純に呼び出します)。それはカプセル化であり、「プライベートで、保護され、公開」だとは言わなかったことに注意してください。
ECMAScript仕様の現在のバージョンは、プライベート、保護された、公開修飾子を定義していません。
ただし、実際には、「JSカプセル化を模倣する」という名前のものを見ることができます。一般に、このコンテキストの目的は使用されることです(原則として、コンストラクター自体)。残念ながら、この「模倣」を実装することがよくあり、プログラマーは「Getter/Setterメソッド」を設定するために擬似的に絶対に補償されていないエンティティを生成できます(もう一度、それは間違っています):
コードコピーは次のとおりです。
関数a(){
var _a; //「プライベート」a
this.geta = function _geta(){
_a;
};
this.seta = function _seta(a){
_a = a;
};
}
var a = new a();
a.seta(10);
アラート(A._a); //未定義、「プライベート」
alert(a.geta()); // 10
したがって、作成された各オブジェクトについて、GETA/SETAメソッドも作成されていることを誰もが理解しています。これがメモリの増加の理由でもあります(プロトタイプ定義と比較して)。ただし、理論的には、最初のケースではオブジェクトを最適化できます。
さらに、いくつかのJavaScriptの記事は、しばしば「プライベート方法」の概念に言及しています。注:ECMA-262-3標準は、「プライベート方法」の概念を定義していません。
ただし、JSはイデオロギー言語であるため、コンストラクターで作成できます。オブジェクトは完全に変化し、独自の特性を持っています(コンストラクターの特定の条件下では、一部のオブジェクトは追加の方法を取得できますが、他のオブジェクトはできません)。
さらに、JavaScriptでは、セッターメソッドを使用する代わりに悪意のあるハッカーが特定の値を自動的に書き込むのを防ぐ方法としてカプセル化がまだ誤って解釈されている場合、いわゆる「隠された」および「プライベート」は「隠されていません」。一部の実装は、評価関数(Spidermonkey 1.7でテストできる)を呼び出すことにより、関連するスコープチェーン(および対応するすべての変数オブジェクト)の値を取得できます。
コードコピーは次のとおりです。
eval( '_ a = 100'、a.geta); //またはa.seta、[_a "メソッドの[[scope]]
a.geta(); // 100
または、実装では、オブジェクトの対応するプロパティにアクセスすることにより、アクティブオブジェクト(Rhinoなど)に直接アクセスできるようにします。内部変数の値を変更できます。
コードコピーは次のとおりです。
// Rhino
var foo =(function(){
var x = 10; // "プライベート"
return function(){
print(x);
};
})();
foo(); // 10
foo .__親__。x = 20;
foo(); // 20
JavaScriptでは、変数を強調することで「プライベート」と「保護された」データの目的が達成されることがあります(ただし、Pythonと比較して、これは単なる命名仕様です):
var _myprivatedata = 'testString';
多くの場合、実行コンテキストを括弧で囲むために使用されますが、実際の補助データの場合、オブジェクトとの直接的な関連性はなく、外部APIから抽象化するのに便利です。
コードコピーは次のとおりです。
(関数 () {
//コンテキストを初期化します
})();
複数の継承
多材料は、コードの再利用の改善に非常に便利な構文糖です(一度に1つのクラスを継承できる場合、なぜ一度に10を継承できないのですか?)。ただし、複数の相続財産の欠点により、実装では人気がありません。
ECMAScriptは、祖先のセルフプログラミング言語にはそのような機能があるが、複数の継承をサポートしていない(つまり、直接プロトタイプとして使用できるオブジェクトは1つだけ)。ただし、__nosuchmethod__を使用したいくつかの実装(Spidermonkeyなど)では、スケジューリングを管理し、プロトタイプチェーンを置き換えるために委任することができます。
ミキシン
ミックスインは、コードを再利用する便利な方法です。ミックスインは、多発性相続の代替として推奨されています。これらの独立した要素はすべて、任意のオブジェクトと混合して機能を拡張できます(したがって、オブジェクトは複数のミックスインも混ぜることができます)。 ECMA-262-3仕様は「ミキシン」の概念を定義するものではありませんが、Mixinsの定義とECMAScriptによると動的な可変オブジェクトがあるため、ミキシンを使用して機能を拡張するだけの障害はありません。
典型的な例:
コードコピーは次のとおりです。
//増強のヘルパー
object.extend = function(destination、source){
(ソースのプロパティ)if(source.hasownproperty(プロパティ)){
宛先[プロパティ] =ソース[プロパティ];
}
宛先を返す;
};
var x = {a:10、b:20};
var y = {c:30、d:40};
object.extend(x、y); // yをxに混ぜます
アラート([xa、xb、xc、xd]); 10、20、30、40
ECMA-262-3で言及されている引用で、これらの定義(「Mixin」、「Mix」)を取得したことに注意してください。仕様にはそのような概念はありません。ミックスではなく、新しい機能を通じてオブジェクトを拡張するための一般的に使用される方法です。 (Rubyのミキシンの概念は公式に定義されています。Mixinは、モジュールのすべての属性を別のモジュールにコピーするだけでなく、モジュールへの参照を作成します。実際、デリゲートに追加のオブジェクト(プロトタイプ)を作成します)。
特性
特性と混合物には同様の概念がありますが、多くの機能があります(定義上、ミックスインを適用できるため、命名競合を引き起こす可能性があるため、状態を含めることができないため)。 ECMAScriptによると、特性とミックスインは同じ原則に従っているため、仕様は「特性」の概念を定義しません。
インタフェース
いくつかのoopsに実装されているインターフェイスは、ミキシンと特性に似ています。ただし、ミキシンや特性と比較して、インターフェイスは実装クラスを強制して、メソッドの署名動作を実装します。
インターフェイスは、抽象クラスと見なすことができます。ただし、抽象クラス(抽象クラスのメソッドはそれらの一部のみを実装でき、他の部分は署名として定義されています)と比較して、継承は単一の継承ベースクラスのみになりますが、複数のインターフェイスを継承できます。これが、インターフェイス(混合倍数)が複数の継承の代替と見なすことができる理由です。
ECMA-262-3標準は、「インターフェイス」の概念も「抽象クラス」の概念を定義していません。ただし、模倣として、「空の」メソッド(または空のメソッドにスローされた例外が、この方法を実装する必要があることを開発者に伝えるオブジェクトによって実装できます。
オブジェクトの組み合わせ
オブジェクトの組み合わせは、動的コードの再利用技術の1つでもあります。オブジェクトの組み合わせは、動的で可変の代表団を実装する柔軟性の高い継承とは異なります。また、これは主要なプロトタイプにも基づいています。動的な可変プロトタイプに加えて、オブジェクトはデリゲート集計オブジェクト(結果として組み合わせを作成する - 集約)にすることができ、さらにオブジェクトにメッセージを送信し、デリゲートに委任します。これは、その動的な性質が実行時に変更できると判断するため、2人以上の代表者になる可能性があります。
言及された__nosuchmethod__の例はこのようなものですが、代表者を明示的に使用する方法を示すこともできます。
例えば:
コードコピーは次のとおりです。
var _delegate = {
foo:function(){
alert( '_ delegate.foo');
}
};
var gregate = {
代表者:_DELEGATE、
foo:function(){
this.delegate.foo.call(this)を返します。
}
};
aggregate.foo(); // Delegate.foo
aggregate.delegate = {
foo:function(){
アラート( 'foo from new Delegate');
}
};
aggregate.foo(); //ニューデリゲートのfoo
このオブジェクトの関係は「has-a」と呼ばれ、統合は「is-a」の関係です。
ディスプレイの組み合わせがないため(継承と比較して柔軟性)、中間コードを追加しても問題ありません。
AOP機能
アスペクト指向の関数として、関数デコレータを使用できます。 ECMA-262-3仕様には、「関数デコレータ」の明確に定義された概念はありません(Pythonとは対照的に、単語はPythonで公式に定義されています)。ただし、機能的なパラメーターを持つ関数は装飾的であり、いくつかの方法で(いわゆる提案を適用することによって)活性化されます。
デコレーターの最も単純な例:
コードコピーは次のとおりです。
function checkdecorator(originalfunction){
return function(){
if(foobar!= 'test'){
アラート( '誤りパラメーター');
falseを返します。
}
originalFunction()を返します。
};
}
function test(){
アラート( 'テスト関数');
}
var testwithCheck = checkdecorator(test);
var foobar = false;
テスト(); //「テスト関数」
testWithCheck(); //「間違ったパラメーター」
foobar = 'test';
テスト(); //「テスト関数」
testWithCheck(); //「テスト関数」
結論は
この記事では、OOPの紹介を整理しました(この情報があなたにとって有用であることを願っています)。次の章では、オブジェクト指向のプログラミングにECMAScriptを実装し続けます。