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データベースパーティションとテーブルパーティション分割方法

推薦する

Linux でローカル コンピューターとリモート サーバーのポートが接続されているかどうかを確認する方法

以下のように表示されます。 1. ssh -v -p [ポート番号] [ユーザー名]@[IPアドレス...

ViteでReactプロジェクトを構築する方法

目次序文Viteプロジェクトを作成する改修プロジェクトディレクトリの規則その他の構成序文毎日鳩、火ば...

GET POSTの違い

1. Get はサーバーからデータを取得するために使用され、Post はサーバーにデータを渡すために...

VMware Workstation Pro が Windows で実行されない場合の解決策

国慶節の休暇後、Windows アップデート後に VMware 仮想マシンが開けなくなり、「VMwa...

MySQLにおける区切り文字の定義と機能の詳細な説明

MySQL を初めて学ぶときは、区切り文字の本当の目的を理解していないかもしれません。区切り文字は、...

初心者向け入門チュートリアル: ドメイン名の解決とバインディング

では、ドメイン名を登録して仮想ホストを購入した後、IE でドメイン名を入力して Web サイトを開く...

MySQL でスロークエリログを有効にする方法

1.1 はじめにスロークエリログを有効にすると、MySQL は指定された時間を超えるクエリステートメ...

MySQLのグローバルロックとテーブルロックに関する詳細な理解

序文ロックの範囲に応じて、MySQL のロックは、グローバル ロック、テーブル ロック、行ロックに大...

Ubuntu20.04 VNCのインストールと設定の実装

VNC はリモート デスクトップ プロトコルです。 VNC を使用して Ubuntu 20.04 を...

CSS3は、ズームと回転を実現するためにscale()とrotate()を使用します。

1. scale() メソッドズームとは「縮小」と「拡大」を意味します。 CSS3 では、scal...

JS における ES6 継承と ES5 継承の違い

目次継承ES5 プロトタイプ継承ES6 クラス継承両者の違いES5プロトタイプ継承の内部実装ES6 ...

HTML CSS3は画像表示効果を引き伸ばさない

1. transform 属性を使用して、画像を拡大せずに表示します (パスの問題は必要に応じて修正...

表内のコンテンツオーバーフローのレイアウト方法について

コンテンツオーバーフローとは何ですか?実際、テキストが大量にある場合、コンテンツ領域がそれだけの長さ...

JavaScript シングルスレッドと非同期の詳細

目次1. タスクキュー2. 混乱を招く問題を説明する1. setTimeout(f1,0)とは何です...

MySQL 8.0 の新機能の落とし穴と解決策についての簡単な説明 (要約)

1. ユーザーを作成して承認するMySQL 8.0 では、ユーザーの作成と認証が以前とは異なります...