ホームページ >ウェブフロントエンド >jsチュートリアル >jsクラス継承の具体的な実装方法_基礎知識

jsクラス継承の具体的な実装方法_基礎知識

WBOY
WBOYオリジナル
2016-05-16 17:06:06930ブラウズ

コードをいじり始める前に、継承を使用する目的と利点を理解する必要があります。一般に、クラスを設計するときは、コードの繰り返しを減らし、クラス間の結合を弱めるように努めます。両方のバランスをとることは困難であり、具体的な条件や状況に応じてどのような方法をとるかを決定する必要があります。オブジェクト指向言語における継承の理解によれば、継承はクラスの直接的な強結合をもたらしますが、js はその独特の柔軟性により、強結合と弱結合、高効率と低効率のコードを設計できます。何を使うかは状況によって異なります。

js で継承を実装するには、クラス継承、プロトタイプ継承、メタクラスの 3 つの方法があります。ここでは最初にクラス継承について簡単に説明し、最後の 2 つについては後で簡単に説明します。ご理解とご指導をお願いいたします。

古典的な継承。

js クラスの継承の実装は、プロトタイプ チェーンに依存します。プロトタイプチェーンとは何ですか? js のオブジェクトには、prototype と呼ばれる属性があり、この属性はオブジェクト タイプへの参照を返し、オブジェクトのクラスの基本関数のセットを提供するために使用されます。

プロトタイプの印象があるようです ちなみに、こんなコードをよく使います。

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

var Person = function(){
this. name = "liyatang";
};
person.prototype = {
// Person の基本関数はここで提供できます
getName: function(){
return this .name;
}
}

クラスの基本関数をプロトタイプ属性に配置し、Person オブジェクトへの参照に XXX 関数があることを示します。

プロトタイプを理解した後は、プロトタイプ チェーンとは何かを理解する必要があります。オブジェクトのメンバー (プロパティまたはメソッド) にアクセスするときに、このメンバーが現在のオブジェクト内に見つからない場合、js は、prototype 属性が指すオブジェクト内でそのメンバーを検索します。まだ見つからない場合は、引き続き検索します。次のレベルのプロトタイプを、指定されたオブジェクトが見つかるまで検索します。見つからない場合は、unknown が返されます。

では、プロトタイプチェーンはどのようなヒントを与えてくれるでしょうか?プロトタイプ チェーンとは、あるクラスが別のクラスを継承するには、親クラスのインスタンスを指すようにサブクラスのプロトタイプを設定するだけでよいことを意味すると考えるのは簡単です。これにより、親クラスのメンバーが子クラスにバインドされます。子クラスでメンバーが見つからない場合は、親クラスで検索されるためです。 (上記 2 つの段落の文言は厳密なものではなく、わかりやすく説明したものです)

次に、中国語クラスが必要です。これは、Person クラスの name メンバーと getName メンバーを継承する必要があります。

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

var Chinese = function(name,nation) {
//継承、親クラスのコンストラクターを呼び出す必要があります。これは call で呼び出すことができます。これは中国語を指します
// person がこのスコープ内にある場合にのみ、person Person.call(this,name );
this.nation =nation;
};
Chinese.prototype = Person.prototype;
//これは以前と同じであることはできません。プロトタイプ属性は上書きされます
//中国語 .prototype = {
// getNation : function(){
// return this.nation;
// }
//};
//後続のメソッドはすべて次のように追加する必要があります
Chinese.prototype.getNation = function(){
return this.nation;
};

継承関係が確立されると、このように呼びます

コードをコピーします コードは次のとおりです。
var c = new Chinese("liyatang" ,"中国 ");
alert(c.getName());// liyatang

これでクラスの継承は完了です。本当に完了したのでしょうか? firebug を使用してアラートにブレークポイントを設定すると、元の Person.prototype が変更され、getNation メソッドが追加されていることがわかります。


jsクラス継承の具体的な実装方法_基礎知識

これは、上記のコードでは Chinese.prototype = Person.prototype; が参照型であるためです。これ自体は容認できず、クラス間に強い結合が生じますが、これは私たちが望む結果ではありません。

新しいオブジェクトを作成したり、インスタンスをインスタンス化して結合を弱めることができます。


コードをコピー コードは次のとおりです:
//最初のタイプ
//中国語。prototype = new Person();
//2 番目の型
//var F = function(){};
//F.prototype = Person.prototype;
//中国語。プロトタイプ = F.prototype;

これら 2 つの方法の違いは何ですか。 2 番目のタイプでは、空の関数 F が追加されます。これにより、親クラスのインスタンスの作成が回避されます。これは、親クラスが比較的大きい可能性があり、親クラスのコンストラクターに副作用が発生したり、大量の処理が実行されたりするためです。計算。したがって、2 番目の方法を強くお勧めします。

これで終わりです、まだ終わっていません!オブジェクトのプロトタイプ属性の下には属性コンストラクターがあり、特定のオブジェクト インスタンスを構築する関数への参照を保持します。このステートメントによると、Chiese.prototype.constructor は中国語と等しいはずですが、そうではありません。

Chiese のプロトタイプ チェーンをセットアップするときに、Chiese.prototype を person.prototype で上書きしたことを思い出してください。したがって、この時点の Chiese.prototype.constructor は person です。次のコードも追加する必要があります

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

//勉強する必要はありませんif 条件の詳細については、ご存知のとおり、 Chinese.prototype.constructor = Chinese
if( Chinese.prototype.constructor == Object.prototype.constructor){
Chinese.prototype.constructor = Chinese;
です。 }

すべてのコードを次のように整理します

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

var Person = function( name){
this.name = name;
};
Person.prototype = {
getName : function(){
return this.name;
}
} ;

var Chinese = function(name,nation){
person.call(this,name);
this.nation =nation;
};
var F = function (){};
F.prototype = person.prototype;
Chinese.prototype = F.prototype;
if( Chinese.prototype.constructor == Object.prototype.constructor ){
中国語 .prototype.constructor = Chinese;
}
Chinese.prototype.getNation = function(){
return this.nation;
};

var c = new Chinese(" liyatang","China");
alert(c.getName());

継承したコードを関数に配置してコードの再利用を容易にできる場合、最終的なコードは次のように構成されます

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

function extend(subClass,superClass){
var F = function(){};
F.prototype = superClass.prototype;
subClass.prototype = new F();
subClass.prototype.constructor = subClass;
サブクラス。 superclass = superClass .prototype; //親クラス関数を呼び出すために、親クラス自体を指す追加の属性を追加します
if(superClass.prototype.constructor == Object.prototype.constructor){
superClass .prototype.constructor = superClass;
}
}

var Person = function(name){
this.name = name;
};
Person.prototype = {
getName : function( ){
return this.name;
}
};

var Chinese = function(name,nation){
Person.call( this,name);
this.nation =nation;
};
extend(中国語, 人);
Chinese.prototype.getNation = function(){
return this.nation;
};

var c = new Chinese("liyatang","China");
alert(c.getName());

公開後に改訂されました:

1 階のコメントの下に、拡張機能に関する新しい見解があります。以前、プロトタイプ チェーンのセットアップ方法について議論したときに 2 つの方法が提案されました

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

//最初のタイプ
//中国語。prototype = new Person();
//2 番目の型
//var F = function(){};
//F.prototype = Person.prototype;
//中国語。プロトタイプ = F.prototype;

2 番目のメソッドは親クラスのコンストラクターを呼び出す必要性を減らしますが、中国語クラスの設計時に Person.call(this,name) が使用されました。これは親クラスのコンストラクターを呼び出すことと同じです。

ただし、最初の方法を使用すると、コードのこの部分はサブクラスで忘れられることがよくあります。この関数コードを extend に置くこともできます。

と書くだけです

Chinese.prototype = new Person(); も同じ目的を達成します。結合は強くありません。

しかし、忘れられているのは、 Chinese.prototype = new Person(); が正しく書かれていることです。答えはノーです!明らかに、 new Person() は name パラメータを渡す必要があります。この部分の作業は extend 関数では実行できないため、中国語クラスの親クラスのコンストラクターを呼び出す必要があります。これはオブジェクト指向の考え方とも一致しています。

したがって、やはり 2 番目の方法を使用することを強くお勧めします。

このような技術的な記事を書くのは初めてなので、基本的には自分の考えに基づいて開発していますが、考慮されていない部分や不明瞭な説明は避けられないと思います。フィードバック用のメッセージ、ありがとうございます。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。