js で継承を実装する 5 つの方法

js で継承を実装する 5 つの方法

コンストラクタの借用

この手法の基本的な考え方は単純です。サブタイプ コンストラクター内からスーパータイプ コンストラクターを呼び出します。また、関数は特定の環境でコードを実行するオブジェクトにすぎないため、apply() メソッドと call() メソッドを使用すると、新しく作成されたオブジェクトでコンストラクターを実行することもできます。

関数 Box(名前){
 this.name = 名前
}
ボックスプロトタイプ年齢 = 18

関数デスク(名前){
 Box.call(this, name) // オブジェクトの偽装、オブジェクトの偽装はコンストラクタ内の情報のみを継承できます}

var デスク = 新しいデスク('ccc')
console.log(desk.name) // --> ccc
console.log(desk.age) // --> 未定義

このことから、インスタンス プロパティのみが継承され、プロトタイプのプロパティにはアクセスできないことがわかります。このパターンは 2 つの問題を解決します。パラメータの受け渡しと継承は可能ですが、プロトタイプがないと再利用できません。

コンポジション継承

関数 Box(名前){
 this.name = 名前
}
Box.prototype.run = 関数 (){
 console.log(this.name + '実行中...')
}

関数デスク(名前){
 Box.call(this, name) // オブジェクトの偽装}

Desk.prototype = new Box() // プロトタイプチェーン var desk = new Desk('ccc')
console.log(desk.name) // --> ccc
desk.run() // --> ccc が実行中です...

この継承方法の背後にある考え方は、プロトタイプ チェーンを使用してプロトタイプ プロパティとメソッドを継承し、コンストラクターを使用してインスタンス プロパティを継承することです。

プロトタイプ継承

プロトタイプの継承: プロトタイプを使用すると、カスタム タイプを作成しなくても、既存のオブジェクトに基づいて新しいオブジェクトを作成できます。これについて言えば、ある人物について言及しなければなりません。Douglas Crockford 氏は、2006 年に執筆した記事「Javascript でのプロトタイプ継承」で、次のようなメソッドを紹介しました。

function object(o) { // リテラル関数を渡す function F(){} // コンストラクターを作成する F.prototype = o; // リテラル関数をコンストラクターのプロトタイプに割り当てる return new F() // 最後にインスタンス化されたコンストラクターを返す }

次の例を考えてみましょう。

関数obj(o) {
 関数F(){}
 F.プロトタイプ = o;
 新しいF()を返す
}

var ボックス = {
 名前: 'ccc',
 年齢: 18歳
 家族: ['兄弟','姉妹']
}

var box1 = obj(ボックス)
console.log(box1.name) // --> ccc
box1.family.push('姉妹')
console.log(box1.family) // --> ["兄弟", "姉妹", "姉妹"]

var box2 = obj(ボックス)
console.log(box2.family) // --> ["兄弟", "姉妹", "姉妹"]

上記コードの実装ロジックはプロトタイプチェーン継承と非常に似ているため、参照配列、つまりファミリ属性が共有されます。

寄生遺伝

関数obj(o) {
 関数F(){}
 F.プロトタイプ = o;
 新しいF()を返す
}
関数create(o){
 var clone = obj(o) // 関数を呼び出して新しいオブジェクトを作成します clone.sayName = function(){ // 何らかの方法でこのオブジェクトを強化します console.log('hi')
 }
 return clone // このオブジェクトを返す }

var 人 = {
 名前: 'ccc',
 友達: ['aa','bb']
}

var anotherPerson = create(人)
anotherPerson.sayName() // --> こんにちは

この例のコードは、person に基づいて新しいオブジェクト anotherPerson を返します。新しいオブジェクトには person のすべてのプロパティとメソッドがあるだけでなく、独自の sayHi() メソッドもあります。寄生継承は、カスタム型やコンストラクターではなくオブジェクトを主に考慮する状況でも役立つパターンです。寄生継承を使用してオブジェクトに関数を追加すると、関数を再利用できないため効率が低下します。これはコンストラクター パターンに似ています。

寄生的組み合わせ継承

前述したように、複合継承は JavaScript で最も一般的に使用される継承モードですが、独自の欠点もあります。複合継承の最大の問題は、状況に関係なく、スーパータイプ コンストラクターが 2 回呼び出されることです。1 回はサブタイプ プロトタイプを作成するときに、もう 1 回はサブタイプ コンストラクター内で呼び出されます。はい、サブタイプには最終的にスーパータイプ オブジェクトのすべてのインスタンス プロパティが含まれますが、サブタイプ コンストラクターを呼び出すときにこれらのプロパティを書き換える必要があります。次の例を見てみましょう。

関数SuperType(名前){
 this.name = 名前;
 this.colors = ['赤','黒']
}
SuperType.prototype.sayName = 関数 (){
 console.log(この名前)
}
関数 SubType(名前, 年齢){
 SuperType.call(this, name) // SuperType への 2 回目の呼び出し
 this.age = 年齢
}

SubType.prototype = new SuperType() // SuperTypeへの最初の呼び出し
SubType.prototype.constructor = サブタイプ
SubType.prototype.sayAge = 関数 (){
 コンソールログ(this.age)
}

SuperType コンストラクターが初めて呼び出されると、SubType.prototype は name と colors という 2 つのプロパティを取得します。これらはすべて SuperType のインスタンス プロパティですが、現在は SubType のプロトタイプに配置されています。 SubType コンストラクターが呼び出されると、SuperType コンストラクターが再度呼び出され、新しいオブジェクトにインスタンス属性の名前と色が再度作成されます。したがって、これら 2 つのプロパティは、プロトタイプ内の同じ名前を持つ 2 つのプロパティをマスクします。つまり、名前と色の属性のセットが 2 つあります。1 つはインスタンスにあり、もう 1 つはプロトタイプにあります。これは、SuperType コンストラクターを 2 回呼び出した結果です。この問題の解決策は寄生的組み合わせ継承です。
いわゆる寄生的な組み合わせ継承とは、コンストラクタを借用してプロパティを継承し、プロトタイプ チェーンのハイブリッド形式を通じてメソッドを継承することです。この背後にある基本的な考え方は、サブタイプのプロトタイプを作成するためにスーパータイプのコンストラクターを呼び出す必要はなく、必要なのはスーパータイプのプロトタイプのコピーだけであるということです。基本的に、寄生継承を使用してスーパータイプのプロトタイプから継承し、その結果をサブタイプのプロトタイプに割り当てます。寄生複合遺伝の基本的なパターンは次のとおりです。

関数オブジェクト(o) {
 関数F(){}
 F.プロトタイプ = o;
 新しいF()を返す
}
関数 inheritPtototype(サブタイプ、スーパータイプ){
 var prototype = object(superType.prototype) // オブジェクトを作成 prototype.constructor = subType // オブジェクトを拡張 subType.prototype = prototype // オブジェクトを指定 }

関数SuperType(名前){
 this.name = 名前
 this.colors = ['赤', '白']
}

SuperType.prototype.sayName = function(){
 console.log(この名前)
}

関数 SubType(名前,年齢){
 SuperType.call(これ、名前)
 this.age = 年齢
}

継承Ptototype(サブタイプ、スーパータイプ)

SubType.prototype.sayAge = function(){
 コンソールログ(this.age)
}

var インスタンス = 新しいサブタイプ ('ccc'、18)

instance.sayName() // --> ccc
instance.sayAge() // --> 18
console.log(インスタンス)

コンソールによって出力される構造:

詳細図:

この例の効率性は、SuperType コンストラクターを 1 回だけ呼び出すため、SubType.prototype に不要な冗長プロパティが作成されないことです。同時に、プロトタイプ チェーンは変更されないため、instanceof と isPrototypeOf() は引き続き正常に使用できます。これは多くの大企業が採用している継承方法でもあります。

以上がjsで継承を実装する5つの方法の詳細です。js継承の詳細については、123WORDPRESS.COMの他の関連記事にも注目してください。

以下もご興味があるかもしれません:
  • ネイティブ JavaScript 継承方法とその長所と短所の詳細な説明
  • JavaScriptで継承を実装するいくつかの方法
  • JS継承の実装方法とメリット・デメリットを詳しく解説
  • JavaScript クラス継承の複数の実装方法
  • JavaScriptはプロトタイププロパティを使用して継承操作を実装する例
  • JavaScriptを使用して継承を実装する方法

<<:  Linux ファイルシステムの説明: ext4 以降

>>:  テーブルパーティションとパーティション分割とは何ですか?MySqlデータベースパーティションとテーブルパーティション分割方法

推薦する

CSS3 列を使用したカード ウォーターフォール レイアウトを実装するためのサンプル コード

この記事では、カード ウォーターフォール レイアウトを実現するための CSS3 列のサンプル コード...

Centos6.5 glibc アップグレードプロセスの紹介

目次シナリオ要件glibc バージョンglibcのインストールglibc ソフトリンクシナリオ要件C...

CentOS8 で Docker を使用してオープンソース プロジェクト Tcloud をデプロイするチュートリアル

1. Dockerをインストールする1. 仮想マシンに Centos7 をインストールしました。Li...

VMware ESXi CLI の一般的なコマンドを調べる

目次【共通コマンド】 [一般的な esxi コマンドの概要] [esxcli コマンドの調査] ES...

Reactドラッグフックを実装するための100行以上のコード

序文ソースコードは合計で 100 行強しかありません。これを読めば、react-dnd などの成熟し...

Windowsタイムサーバーの設定方法の詳しい説明

最近、会社のサーバーの時間が不正確で、外部の時間ソースと同期できないことがわかりました。会社はドメイ...

この構成ファイルの排他ロックに失敗したという VMware 仮想マシンのプロンプトの解決方法

VMware が異常シャットダウンした後、再起動すると「この構成ファイルを排他的にロックできませんで...

Bootstrap 3.0 学習ノートボタンスタイル

この記事では主にボタンのスタイルについて説明します。 1. オプション2. サイズ3. 活動状況4....

CentOS6.9 での MySQL 5.7.17 のインストールと設定のチュートリアル

CentOS6.9はMysql5.7をインストールします。参考までに、詳細は次のとおりです。 1. ...

よくあるNginxの設定ミスの例

目次ルートの場所が見つかりませんオフバイスラッシュ安全でない変数の使用スクリプト名$uri を使用す...

Spark SQL の 4 つの一般的なデータ ソースの詳細な説明

汎用ロード/書き込みメソッドオプションを手動で指定するSpark SQL の DataFrame イ...

スケルトンスクリーン効果を実現する CSS

ネットワーク データを読み込むときは、ユーザー エクスペリエンスを向上させるために、通常は円形の読み...

一般的な nginx コマンドをシェル スクリプトに組み込む方法の詳細な説明

1. nginxシェルスクリプトを保存するフォルダを作成する /usr/local/タスク/ngin...

カルーセルアニメーションを実現するVueコンポーネント

この記事では、カルーセルアニメーションを実現するためのVueコンポーネントの具体的なコードを例として...

Web ページのスクロール バーが右側に設定されているのはなぜですか?

私たちが毎日使っているブラウザや Word 文書のスクロール バーはなぜ右側にあるのでしょうか。多く...