考え方:
Javascript や同様の言語では、各オブジェクトには、それ自体がオブジェクトでもあるプロトタイプがあります。オブジェクトのメソッドまたはプロパティにアクセスしようとすると (JavaScript では関数はファースト クラスであるため、メソッドとプロパティの区別は誤解を招きやすいため)、インタープリターがオブジェクト自体を見つけられない場合は、プロトタイプを調べます。プロトタイプもオブジェクトであるため、独自のプロトタイプ (オブジェクト プロトタイプ プロトタイプ) も持ちます。したがって、この一連のプロトタイプがあり、継承の各レベルに 1 つずつ、基本クラスの Object までトレースします。その時点で、アクセスしようとしていたプロパティが見つからない場合、インタープリターは未定義のプロパティ エラーをスローします。
実装方法:
継承を行う方法は多数あります。これは私が使用するもので、必ずしも最適なものではありませんが、最も理解しやすいものです。
//A constructor
var A= function() {};
A.prototype.doSomething= function() { };
A.prototype.doSomethingElse= function() { };
//B constructor
var B= function () {
A.apply(this, arguments); //calls A constructor on this instance of B
};
B.prototype= new A(); //this makes B "extend" A. Basically it sets B prototype to be an instance of A.
B.prototype.doSomething= function() {
A.doSomething.apply(this, arguments); //calling "super"
};
B.prototype.doSomethingElse= function() {
A.doSomethingElse.apply(this, arguments); //calling "super"
};
//C constructor
var C= function () {
A.apply(this, arguments);
};
C.prototype= new A();
C.prototype.doSomething= function() {
A.doSomething.apply(this, arguments); //calling "super"
};
C.prototype.doSomethingElse= function() {
A.doSomethingElse.apply(this, arguments); //calling "super"
};
したがって、Cにメソッド doSomethingElseがなく、次のようにするとします。
c= new C();
c.doSomethingElse();
c インスタンスで A.doSomethingElse メソッドを呼び出します。
.apply 関数の簡単な説明: javascript の関数はオブジェクトを「拡張」します。そのため、それらはオブジェクトそのものです。実際、これを実際に行うことができます:
var myFunc= new Function("alert('myFunc');");
myFunc();
関数はオブジェクトであるため、独自のプロパティとメソッドもあります。「申し込む」もその一つです。
あなたがこれを言うとき:
//A constructor
var A= function() {};
A.prototype.doSomething= function() { };
実際に関数を作成して A に格納し、次に A プロトタイプ内にメソッドを配置します (関数はオブジェクトであるため、プロトタイプがあることを思い出してください)。これを行う場合:
var a= new A(arg1,arg2,arg3...);
A のインスタンスを作成しています。「new」演算子は、基本的にこれを行う特別な種類の演算子です。
a= A.apply(a, [arg1,arg2,arg3,...]);
a.prototype= A.prototype;
Function.apply メソッドの説明は次のとおりです:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply?redirectlocale=en-US&redirectslug=JavaScript%2FReference%2FGlobal_Objects %2F関数%2F適用
そして、ここに渡される「引数」配列の説明があります:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope/arguments
あなたがこれを言うとき:
C.prototype.doSomething= function() {
A.doSomething.apply(this, arguments);
};
この場合の A.doSomething は、 Java の静的関数に似ていることに注意してください。A のインスタンスのメソッドを呼び出しているのではなく、実際にはコンストラクター関数 A に存在するメソッドを呼び出しています (メソッドは実際には A.プロトタイプですが、関数はオブジェクトであるため、インタープリターはプロトタイプでそれ自体を探します)。
コンストラクターは関数であり、関数はオブジェクトであり、オブジェクトにはプロトタイプがあり、プロトタイプはオブジェクトであり、オブジェクトはその内部に関数を持つことができるため、これをすべて行うことができます。クレイジーでしょ?しかし、先に説明したプロトタイプ チェーンについて考えるのをやめれば、それほど難しいことではありません。その文を数回読み直してください。
なぜこのすべてのナンセンスなのですか?
あなたはおそらく今少し混乱しているので、ネットでもっと例を探すことをお勧めします。しかし、これは複雑で過度に複雑であると言うのは簡単です。(javascript では) 複雑ですが、非常に強力でもあります。実行時にオブジェクトの動作を変更できます。
実行時の任意の時点でこの小さなコードを実行すると
A.prototype.doSomething= function() {
A.doSomethingElse.(apply(this, arguments));
}
実際には、A のすべてのインスタンスと、それを継承する他のクラスの動作を変更しています (B と C のすべてのインスタンスも変更されます)。この場合、A.doSomething は A.doSomethingElse とまったく同じように動作します。クレイジーなコードを一切使わずに Java リフレクションを考えてみてください。
実際、String や Array などの Javascript の組み込みクラスの動作を変更できます。プログラムのどこかでこのコードを実行すると、次のようになります。
String.prototype.alert= function() {
alert(this);
}
次のことができるようになりました。ポップアップ ボックスが表示され、その中に「テキスト」が表示されます。ただし、組み込みクラスをそのように変更しないでください。これは悪い習慣です。
これは、プロトタイプ ベースのオブジェクト指向を使用することの多数の利点の 1 つにすぎません。他にもたくさんあります。
プライベートメソッドはどうですか?
これらは JavaScript には存在しませんが、クロージャーを介して別の関数からのみ見える関数を作成できます。プライベート メソッドを作成する必要がある場合は、クロージャについて読むことをお勧めします。