JS 継承の詳細

JS 継承の詳細

序文

柔軟な js の場合、java などの言語と比較して、継承にはさまざまな実装方法があります。方法の多様性は、知識ポイントの多さを意味し、それは当然、面接中に避けることができないポイントです。 ES6 クラスは別として、従来の継承方法をいくつ知っていますか?それぞれの実装原則は何ですか? 利点と欠点についてお話しいただけますか?ここでは、具体的な例を用いて段階的なアプローチで継承の発展について見ていきます。

準備する

js の継承について説明する前に、js がオブジェクトをインスタンス化する方法を確認しましょう。

コンストラクターは、new を通じてオブジェクトをインスタンス化できる関数です。その目的は、それを再利用し、毎回手動でオブジェクト インスタンスを宣言する手間を省くことです。

新しいシンプルな実装は次のとおりです。

関数 my_new(func){
    var obj = {}
    obj._proto_ = func.protype // プロトタイプチェーンポイントを変更し、それを func プロトタイプチェーンに接合します func.call(obj) // インスタンス属性の割り当て return obj
}

上記からわかるように、インスタンス属性はコンストラクター呼び出しを通じてターゲット オブジェクトに割り当てることができます。

サブクラスで親クラスのコンストラクターを呼び出すことでも継承の目的を達成できると推測できます。

これにより、js を継承する方法、つまりコンストラクターを介して呼び出す方法が提供されます。

プロトタイプ属性に関しては、プロトタイプポインタを変更することでプロトタイプ属性の共有が実現されます。

継承にも同じ方法を使用できます。

要約する

コンストラクターとプロトタイプ チェーンの 2 つの機能に基づいており、js 言語の柔軟性と組み合わされています。

継承を実装する方法は多数ありますが、それらはすべて同じ原則に従います。

継承方法

プロトタイプ継承

定義: カスタム タイプを作成せずに、プロトタイプを使用して既存のオブジェクトに基づいて新しいオブジェクトを作成するこのタイプの継承は、プロトタイプ継承と呼ばれます。

コードを直接見たほうがわかりやすいです:

関数createObj(o) {
  関数 F() { }
  F.プロトタイプ = o;
  新しいF()を返します。
}
var 親 = {
  名前: 'trigkit4',
  arr: ['兄弟', '姉妹', 'ババ']
};
var child1 = createObj(親);

表面的には、このメソッドはオブジェクトの作成に基づいており、コンストラクターは必要ありません (もちろん、実際のコンストラクターはカプセル化されています)。プロトタイプオブジェクトのみが使用されるため、名前はプロトタイプ継承です。

欠点:

より明らかな優位性

この継承は再利用できず、各サブクラス インスタンスは完全な createObj プロセスを経る必要があります。

サブクラスオブジェクトの場合

コンストラクターは createObj にカプセル化されているため、そのためのコンストラクターはありません。この結果、初期化中にパラメータを渡すことができなくなります。
補足: createObj は ES6 でよく使用される Object.create() ですが、Object.create は追加のパラメータを許可するように改良されています。

解決:

この問題はコンストラクタの不足によって発生するため、コンストラクタのプロトタイプ チェーン継承が関係しているのではないかと大胆に推測します。

プロトタイプチェーン継承

定義: サブクラスが親クラスのプロパティ (メソッドを含む) を継承するには、まずコンストラクターを定義する必要があります。次に、スーパークラスの新しいインスタンスがコンストラクターのプロトタイプに割り当てられます。

関数親() {
  this.name = 'マイク';
}
関数Child() {
  年齢は12歳です。
}
Child.prototype = 新しい Parent();
child.prototype.constructor = child // prototype プロパティが上書きされるため、修正する必要があります。
var child1 = 新しい Child();

つまり、サブクラスのプロトタイプ オブジェクトを直接変更して親コンストラクターのインスタンスを指すようにし、親クラスのインスタンス属性とプロトタイプ属性が独自のプロトタイプ チェーンに掛けられるようにします。

欠点

Child.prototype = new Parent() の場合、子関数自体の prototype プロパティが上書きされ、必要に応じて後で補足する必要があります。

子オブジェクトがインスタンス化されると、親クラスのコンストラクターにパラメーターを渡すことはできません。
たとえば、new Child() が実行されたときに、名前を上書きしたい場合は、Child.prototype = new Parent() の場合にのみ上書きできます。 新しい Child() を作成するときに、パラメータを均一に渡して初期化することが、より一般的な要件です。

解決

サブクラスが初期化されるときに親クラスのコンストラクターを呼び出す方法。これまでの基盤と組み合わせると、答えは明らかです。

コンストラクタの借用(クラス継承)

クラス継承: サブタイプ コンストラクター内でスーパータイプ コンストラクターを呼び出します。

アイデアは比較的明確であり、問​​題によって推進されています。

プロトタイプチェーンのサブクラスは親クラスにパラメータを渡すことができないため、サブクラスが初期化されるときに親クラスを呼び出すだけで十分ではないでしょうか?

次に例を示します。

関数 Parent(年齢) {
  this.name = ['マイク'、'ジャック'、'スミス'];
  this.age = 年齢;
}
Parent.prototype.run = 関数(){
  this.name + ' は両方とも ' + this.age を返します。
};
関数 Child(年齢) {
  //親クラスを呼び出します Parent.call(this, age);
}
var child1 = 新しいChild(21);

これは初期化中のパラメータ転送のニーズを満たしますが、問題も明らかです。

child1.run //未定義

質問

親クラスのプロトタイプ属性が失われました

親クラスの初期化ではサンプルプロパティのみが継承され、プロトタイププロパティはサブクラスのプロトタイプチェーンで失われます。

解決

損失の理由は、プロトタイプ チェーンがポインターを変更しないためです。では、なぜポインターを変更しないのでしょうか?

コンポジション継承

定義: プロトタイプ チェーンを使用してプロトタイプ プロパティとメソッドの継承を実装し、コンストラクターを使用してインスタンス プロパティの継承を実装します。

例:

関数 Parent(年齢) {
  this.name = ['マイク'、'ジャック'、'スミス'];
  this.age = 年齢;
}
Parent.prototype.run = 関数(){
  this.name + ' は両方とも ' + this.age を返します。
};
関数 Child(年齢) {
  //親クラスのコンストラクターを呼び出します Parent.call(this, age);
}
Child.prototype = new Parent(); //プロトタイププロパティの継承 Child.prototype.constructor = Child
var child1 = 新しいChild(21);

この問題は次のように回避されます。

child1.run() // "マイク、ジャック、スミスは両方とも21です"

質問

機能が満たされたら、パフォーマンスに焦点を当てます。この継承方法の問題は、親クラスのコンストラクターが 2 回実行されることです。

彼らです:

関数 Child(年齢) {
  // 親クラスのコンストラクターを 2 回目に呼び出します。Parent.call(this, age);
}
Child.prototype = new Parent(); //最初に指しているプロトタイプチェーンを変更する

解決

自然な解決策は、1 つのコンストラクター呼び出しをキャンセルすることです。キャンセルするには、当然、2 つの実行を分析して、機能に重複があるかどうかを確認する必要があります。

1 回目はインスタンス プロパティとプロトタイプ プロパティも継承し、2 回目は親クラスのインスタンス プロパティも継承します。

したがって、2 回目は親クラスのパラメータが利用できないため、1 回目は親クラスのコンストラクターを呼び出さず、プロトタイプ プロパティのみを継承する方法についてのみ検討できます。

答えはもちろん「はい」です。以前のプロトタイプ継承はこの考えに基づいています。

寄生的組み合わせ継承

名前が示すように、寄生とはプロトタイプ プロパティを継承するメソッドを特定のメソッドにカプセル化することを指し、組み合わせとはコンストラクタ継承を組み合わせてプロトタイプ継承の欠点を補うことです。

許してください、ただ見てください:

関数createObj(o) {
  関数 F() { }
  F.プロトタイプ = o;
  新しいF()を返します。
}
//プロトタイププロパティの継承、つまりプロトタイプ継承関数 create(parent, child) { 
  var f = createObj(parent.prototype); //プロトタイプオブジェクトを取得する child.prototype = f
  child.prototype.constructor = child; //オブジェクトのプロトタイプを拡張します。つまり、元のコンストラクタが指し示すままにします}

関数 親(名前) {
  this.name = 名前;
  this.arr = ['兄弟', '姉妹', '両親'];
}
Parent.prototype.run = 関数(){
  this.name を返します。
};
関数 Child(名前, 年齢) {
  // 例のプロパティ Parent.call(this, name);
  this.age = 年齢;
}
// このメソッドではプロトタイプ プロパティの継承が寄生します create(Parent.prototype,Child);
var child1 = 新しい Child('trigkit4', 21);

このように、比較的完全な継承方法に到達するまで、問題を発見して解決するという考え方に従います。 ES メソッドについては、この記事では説明しません。

結論

たくさんの積み重ねがあってこそ、多くのことを達成できます。希望するオファーを受けたいなら、十分に準備し、しっかりとした基礎を築かなければなりません。あいまいにしないでください。原則は理解していますが、回答が不完全です。これは、まったく理解していないのとあまり変わりません。それほど新しくないこの時代に、毎週 3 つの知識ポイントを復習するという目標を設定してください。あなたが花を咲かせれば、蝶があなたのところにやって来ると信じてください。

以上が、JS継承の詳細な内容です。JS継承の詳細な内容については、123WORDPRESS.COMの他の関連記事にも注目してください。

以下もご興味があるかもしれません:
  • ネイティブ JavaScript 継承方法とその長所と短所の詳細な説明
  • JavaScript における継承の 3 つの方法
  • jsの継承の6つの方法を詳しく解説
  • JavaScriptで継承を実装するいくつかの方法
  • js で継承を実装する 5 つの方法
  • JavaScript におけるいくつかの継承方法の例
  • JavaScript継承の詳細な説明
  • JavaScript オブジェクト指向クラス継承ケースの説明

<<:  Linux での mysql および mysql.sock のインストールに関する問題

>>:  Linux システム ディレクトリ sys、tmp、usr、var の詳細な説明。

推薦する

Windows での MySQL 5.7.18 インストール チュートリアル

この記事では、圧縮パッケージから MySQL をインストールする方法について説明します。 1. My...

Vue 学習 - VueRouter ルーティングの基礎

目次1. Vueルーター1. 説明2. 選択したルートのレンダリング: 3. 基本的な動作原理2. ...

Linux でコマンドまたはプロセスの実行時間を調べる方法

Unix ライクなシステムでは、コマンドまたはプロセスの実行がいつ開始されたか、またプロセスがどのく...

vue3+TypeScript+vue-routerの使い方

目次使いやすいプロジェクトを作成するvue-cli 作成ヴィートクリエイションvue-routerを...

W3C 検証に合格するにはどうすればいいですか?

W3C では、さまざまなタグの規定を設定するだけでなく、Web ページの作成者が実際に W3C 規...

VUE+Express+MongoDBのフロントエンドとバックエンドの分離によるノートウォールの実現

付箋紙の壁シリーズを実現しようと思っています。シンプルなものはシンプル、複雑なものは多機能です。開発...

シームレスなトークンリフレッシュを実現する方法

目次1. 需要方法1方法2方法3 2. 実装3. 問題解決質問1: トークンの複数回の更新を防ぐ方法...

ポータルサイトのフォーカス画像のデザインに関するいくつかの結論

フォーカス画像は、画像、テキスト、動的なインタラクティブ効果を統合したコンテンツを表示する方法です。...

Vueコンポーネント間の通信の非常に詳細な要約

目次序文1. Props、$emit一方向データフロー2. $親、$子3. $attrs、$list...

自動ロック画面機能を実現するjs

1. 使用シナリオこのような要件があるため、システムが開発されました。ユーザーがデスクトップを離れ...

Dockerイメージの作成、アップロード、プル、デプロイを理解するための記事

目次1. 画像1. 鏡とは何ですか? 2. 画像の構成と目的(1) Dockerファイル(2)スクラ...

iframe に関するいくつかの発見と考察

この物語は、今日の予期せぬ発見から始まります。同社には複数のウェブサイトがある。友達リンクにはお互い...

MySQL 学習のまとめ: InnoDB ストレージ エンジンのアーキテクチャ設計の予備的な理解

1. ストレージエンジン前のセクションでは、SQL 実行プランは、エグゼキュータ コンポーネントがス...

MySQLでインデックスエラーが発生する状況について簡単に説明します

以下に、トレーニング機関からのヒントと私自身の要約をいくつか示します。以下のインデックスの内容を説明...