JavaScriptの継承システムを徹底解説

黄舟
リリース: 2017-10-23 09:39:06
オリジナル
1222 人が閲覧しました

1. コンストラクターのプロトタイプ属性とプロトタイプオブジェクト

初めて js に触れたとき、私は通常、同じ例に従って関数 new を使用してインスタンスを作成します。 jsの関数はオブジェクトであると聞いただけです。 jsはJavaなどの言語のクラス継承システムを使用せず、プロトタイプオブジェクト(プロトタイプ)を使用して継承システムを実装することがわかります。具体的には、「コンストラクター」を使用してクラス関数を実装します。

まず、プロトタイプの継承における 2 つの重要な概念、プロトタイプ属性とプロトタイプ オブジェクト (インスタンス) について説明します。

js オブジェクト システムに関する限り、作成された各関数 (コンストラクター) には、prototype 属性が含まれます。同時に、コンストラクターを通じて作成された各オブジェクト インスタンスには、_proto_ 属性、prototype 属性、および _proto_ 属性も含まれます。プロトタイプオブジェクトを指します。通常の関数とコンストラクターの唯一の違いは、そのプロトタイプ属性のプロトタイプが意味のある値であるかどうかです。

プロトタイプ属性のプロトタイプが指すプロトタイプは、オブジェクトのインスタンスです。具体的には、以下の図に示すように、コンストラクター Animal() にプロトタイプ オブジェクト B がある場合、コンストラクターによって作成されたすべてのインスタンスを B にコピーする必要があります。つまり、Animal() のインスタンス a1 の _proto_ 属性もプロトタイプ オブジェクト B を指します。したがって、インスタンス a1 は、B のすべてのプロパティ、メソッド、およびその他のプロパティを継承できます。

図 1 JS オブジェクトのインスタンス化の実装

2. 空のオブジェクト

JavaScript では、「空のオブジェクト」はプロトタイプ継承システム全体の基礎であり、すべてのオブジェクトの基礎です。 「空のオブジェクト」を導入する前に、まず「空のオブジェクト (null)」を導入する必要があります。

Empty object null

Null は JavaScript の予約語としての「空のオブジェクト」ではありません。その意味は次のとおりです。

(1) オブジェクト型に属します

(2) オブジェクトは null 値です

オブジェクト型として、for...in を使用して列挙できますが、null 値として、null にはメソッドや属性 (コンストラクター、_proto_、その他の属性を含む) がないため、何も列挙できません。次の例に示すように:


var num=0;
  for(var propertyName in null)
  {
  num++;
  }
ログイン後にコピー

Alert(num);//表示される値は0です

最も重要な点は、nullにはプロトタイプがなく、Object()コンストラクター(またはそのサブクラス)、それに対して instanceof 操作を実行すると false が返されます。

2.「空のオブジェクト」

「空のオブジェクト」とは、Object()を通じて構築された標準のオブジェクトインスタンスを指します。例:


obj=new Object();或 obj={};
ログイン後にコピー

「空のオブジェクト」は「オブジェクト」のすべての特性を備えているため、toString() や valueof などの事前定義されたプロパティやメソッドにアクセスできます。

3.「空のオブジェクト」とnullの関係

以下の図2の赤線で示したパスのように、「Object.prototype._proto_」を通じてObjectプロトタイプオブジェクトの-proto-attributeを取得すると、 " とすると、 null オブジェクトには属性がないため、 "null" が返されます。つまり、 "Object {}" です

プロトタイプ オブジェクトは、プロトタイプ チェーンの終端です。

図 2 js クラスの継承システム

3. Javascript の継承の実装とプロトタイプチェーンの保守

(1) 継承の実装

最初のセクションでは、JavaScript におけるクラスの継承は変更によって構築されると述べました関数のプロトタイプ属性プロトタイプが実装されます。次のコードに示すように:


function Animal() {
this.name = 'Animal';
};
function Dog() {
};
  Dog.prototype = new Animal();
var d = new Dog();
console.log(d.name);//'Animal'
ログイン後にコピー

型の継承は、Animal 型のインスタンスを作成し、それをコンストラクター Dog() のプロトタイプ属性に割り当てることによって実現されます。つまり、Animal は Dog の親クラスです。このようにして、Dog タイプのインスタンス d も、Animal タイプの name 属性にアクセスできます。

(2) プロトタイプチェーン

JSオブジェクト継承システムには、「内部プロトタイプチェーン」と「コンストラクタープロトタイプチェーン」の2つのプロトタイプチェーンがあります。図 3 に示すように、黒い矢印は、パスがコンストラクターのプロトタイプ属性によって維持される「コンストラクター プロトタイプ チェーン」であることを示します。赤い矢印は、パスがオブジェクト インスタンスの _proto_ 属性を通じて維持される「内部プロトタイプ チェーン」であることを示します。

図 3 プロトタイプ チェーン

(3) プロトタイプ チェーンのメンテナンス

図 3 は、コンストラクターが表示されたプロトタイプを通じてプロトタイプ チェーンを構築し、オブジェクト インスタンスも _ proto _ 属性を通じてプロトタイプ チェーンを構築することを示しています。 _ proto _ はアクセスできない内部プロパティであるため (object _ proto _ プロパティの値は Chrome で表示できますが、変更することはできません)、サブクラス (Dog) のインスタンス Dog1 から始まるプロトタイプ チェーン全体にアクセスすることはできません。したがって、図 3 の「内部プロトタイプ チェーン」と「コンストラクター プロトタイプ チェーン」から接続ポイントを見つけて、インスタンスが obj._proto_ にアクセスできない場合に、コンストラクター (2 つのプロトタイプ) を介して内部プロトタイプ チェーンにアクセスできるようにする必要があります。は直列にチェーンされています)。

サブクラスのインスタンスから開始してプロトタイプ チェーン全体にアクセスするには、インスタンスのコンストラクター属性を使用してプロトタイプ チェーンを維持する必要があります。

其实,JavaScript已经为构造器维护了原型属性,根据如下测试代码,当我们自定义一个构造器时,其原型对象是一个Object()类型的实例,但是其原型对象的constructor属性默认总是指向构造器自身,而非指向其父类Object。如图4中构造器实例中蓝色框中的constructor属性,该constructor属性继承自原型对象,因此可以得出一个自定义的构造器产生的实例,其constructor属性默认总是指向该构造器。


function Animal() {
};
var a = new Animal();
console.log(Animal.prototype);//Object(){}
console.log(Animal.prototype.constructor === Animal);//true//true
ログイン後にコピー

  

图4

  因此,在_proto_属性不可访问时,可通过a1.constructor.prototype获取实例a1的原型对象。然而,当我们自定义一个构造函数Dog(),并且手动指定其prototype属性值为Animal,即指定Dog的父类为Animal。此时访问d1.constructor值为Animal,而不是Dog;由图5可以看出,Dog的原型对象和dog分别由Animal()和Dog()两个不同的构造器产生,然而他们的constructor属性指向了相同的构造器(Animal),这样就与使用constructor属性串联两种原型链的设想冲突了。

图5

  是构造器出问题还是原型出了问题?图5可以看出,原型继承要求的“复制行为”已经正确实现,能够从子类实例中访问原型对象属性,问题是在给子类构造器Dog()赋予一个原型对象时应该“修正”该原型对象的构造属性值(constructor)。ECMAScript 3标准提供的方法是:保持原型的构造器属性,在子类构造器中初始化其实例对象的构造属性。代码如下: 


function Dog () {
  //初始化constructor属性
   this.constructor=Dog; //或 this.constructor=arguments.callee;
  };
  Dog.prototype = new Animal();//赋予原型对象,实现继承
ログイン後にコピー

图6

对constructor属性“修正”后效果如图6所示,在子类构造器Dog中初始化其实例对象的constructor属性后,Dog的实例对象的constructor都指向Dog,而Dog的原型对象的constructor仍然指向父类型构造器Animal。这样就可以实现利用constructor属性串联起原型链,可以从子类实例开始回溯整个原型链。

总结

以上がJavaScriptの継承システムを徹底解説の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート