記事ディレクトリ
プライマー
興味深いことに、JavaScript のオブジェクト指向設計の考え方は、他のオブジェクト指向言語 (Java、Python など) の考え方とは異なります。
JavaScript はオブジェクト指向言語ですが、JavaScript はクラスを使用したり、クラスを作成したり、クラスを通じてオブジェクトを作成したりしません。幸いなことに、Es6の登場によりこの状況は変わりました(公式も元々のJavaScriptのデザインが少し味気ない、と感じていたようです)。Es6 より前は、JavaScript のオブジェクト指向の一連の問題 (オブジェクトの一意性、抽象化、継承、ポリモーフィズム) を解決するには、プロトタイプ チェーンを使用する必要がありました。プロトタイプチェーンの最大の役割は、オブジェクトの継承の問題を解決することです。
JavaScript では、すべてがオブジェクトです。コンストラクター (Function) はオブジェクトであり、コンストラクターのプロトタイプ オブジェクト (Function.prototype) もオブジェクトです。オブジェクトは __proto__ という属性を持ち、 __proto__ はオブジェクトを構築するコンストラクターのプロトタイプ オブジェクトを指し、コンストラクターには、独自のプロトタイプ オブジェクトを指す属性prototypeが含まれます。プロトタイプ オブジェクトには属性コンストラクターがあり、プロトタイプ オブジェクトに関連付けられたコンストラクター (constructor.prototype.constructor==constructor) を指します。__proto__ はすべてのオブジェクトが持つ属性、prototype は関数またはコンストラクターのみが持つ属性、constructor はプロトタイプ オブジェクトのみが持つ属性であることに注意してください。
Es6 が以前どのように継承を実装したかを説明するために、コンストラクターとは何なのか、プロトタイプ オブジェクトとは何なのかを 1 つずつ説明しましょう。
コンストラクタ
他のオブジェクト指向言語とは異なり、JavaScript では新しいクラスを使用してオブジェクトを生成するのではなく、新しい関数を使用してオブジェクトを生成します。新しい関数をコンストラクターと呼び、生成されたオブジェクトをコンストラクター インスタンス オブジェクトと呼びます。
関数がコンストラクターとして使用される場合、その関数内の this ポインターは window や unknown を指すのではなく、作成されたインスタンス オブジェクトを指すことに注意してください。
次の例のように、Person は atuo のコンストラクターであり、atuo は Person のインスタンス オブジェクトです。
function Person(name){
this.name = name
}
var atuo = new Person("atuo")
プロトタイプオブジェクト
コンストラクターには、コンストラクターのプロトタイプ オブジェクトを指すプロトタイプ属性があります。つまり、いわゆるプロトタイプ オブジェクトがプロトタイプ オブジェクトであり、コンストラクターによって生成されたインスタンス オブジェクトは、コンストラクターを介してコンストラクターを指します。 __proto__ プロトタイプ オブジェクト。
すべてのインスタンス オブジェクトはコンストラクターの同じプロトタイプ オブジェクトを共有するため、一般的には、プロトタイプ オブジェクトに固定で不変の属性値を配置し、すべてのインスタンス オブジェクトがそれを継承するようにします。この属性は参照属性とも呼ばれます。プロトタイプ オブジェクトは、インスタンス オブジェクトの共有変数およびメソッドとして理解され、独自のニーズに応じて動的に変更できるさまざまなインスタンス オブジェクトの属性値がコンストラクターに配置され、この属性はローカル属性。インスタンスが特定の属性を検索するときに、そのローカル属性が見つからない場合は、参照属性を検索します。つまり、インスタンスを構築するコンストラクターのプロトタイプ オブジェクトを検索します。この点については、 JavaScript の継承メカニズムの設計思想を利用できます。
function Person(name){
this.name = name
}
Person.prototype.age = 21
var atuo = new Person("atuo")
console.log(atuo.age)
上記の atuo インスタンスにローカル属性名と参照属性 age がある場合、age を検索するときに、そのコンストラクターの属性で見つからない場合 (つまり、ローカル属性で見つからない場合)、追跡されます。コンストラクターのプロトタイプ オブジェクトに戻ります。それは Person.prototype で見つかります。
コンストラクター、プロトタイプ オブジェクト、インスタンス オブジェクトの関係を図に示します。
プロトタイプチェーン
上記のコンストラクタ、プロトタイプオブジェクト、インスタンスオブジェクトの関係を合成します。では、あるコンストラクターのプロトタイプ オブジェクトを別のコンストラクターのインスタンスと等しくするとどうなるでしょうか? 当然、このときのプロトタイプオブジェクトには、別のコンストラクタのプロトタイプオブジェクトを指すポインタ __proto__ が含まれており、これに対応して、プロトタイプオブジェクト間のチェーンもこのような漸進的な進行によって形成されます。プロトタイプ オブジェクトのチェーンは、__proto__ のチェーンに沿って進行します。これがいわゆるプロトタイプチェーンの基本概念です。
プロトタイプ チェーンを説明するために、次のコードを例に挙げます。
function Student(name){
this.name = name
}
Student.prototype.hello = function(){
alert('Hello, ' + this.name + '!');
};
var xiaoming = new Student("xiaoming")
var xiaohong = new Student("xiaohong")
以下の図に示すように、黄色でマークされた線がプロトタイプ チェーンです。
継承する
上記では、プロトタイプ チェーンの関連概念を簡単に説明しましたが、次に、プロトタイプ チェーンを使用して 2 つの「クラス」の継承を実装します。親コンストラクターと子コンストラクターがある場合、それらは互いに何の関係もありません。図に示すように、プロトタイプ チェーンは重なっていません。
2 つのプロトタイプ チェーンが重なるように、子が親から継承するようにコードを記述します。
function extend(Child, Parent) {
var F = function(){
};
F.prototype = Parent.prototype;
Child.prototype = new F();
Child.prototype.constructor = Child;
Child.uber = Parent.prototype;
}