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 の詳細な説明。

推薦する

HTML スクロールバーのテキストエリア属性の設定

1.オーバーフローコンテンツのオーバーフロー設定(設定されたオブジェクトにスクロールバーを表示するか...

ボタンのタイプが送信として指定されていません。ボタンをクリックしても、指定された URL にジャンプしません。

現在、プロジェクトの要件により、フォームの送信を制御し、送信前にデータを検証および処理するために j...

Mysqlのprepare前処理の具体的な使用法

目次1. 前処理2. 前処理塗布方法A. 例: B. 実行計画の変更を追跡するための前処理C. スト...

MySQL 文字セットの概要

目次文字セット比較ルール4つのレベルの文字セットと比較規則3つのシステム変数このノートは主にMySQ...

HTML+CSS ボックスモデルの例 (円、半円など) 「border-radius」はシンプルで使いやすい

多くの友人は、フロントエンドを学習するときに、ボックス モデルがデフォルトで正方形であることに気付き...

JSフロントエンドモジュール化のいくつかの仕様についての簡単な説明

目次序文フロントエンドモジュール開発の価値厄介な名前の競合面倒なファイル依存関係モジュール化の利点C...

MySQL 分離レベル操作プロセスの詳細説明 (cmd)

コミットされていない読み取りの例の操作プロセス - コミットされていない読み取り1. 2 つの My...

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

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

Tomcat が応答データグラムを書き戻すタイミングの詳細な分析

疑問が生じるこの質問は、ファイルのダウンロードを記述しているときに発生しました。HttpServle...

Dockerの国内イメージソースを変更する方法

Dockerデーモンのアクセラレータを構成する設定ファイルから Docker を起動し、/etc/d...

シンプルなID生成戦略: MySQLテーブルからグローバルに一意のIDを生成する実装

グローバル ID を生成する方法は多数あります。ここでは簡単な解決策を紹介します。MySQL の自動...

Vue でフルスクリーンを実装し、フルスクリーン終了を監視する

目次序文:実装手順:完全なソースコード:詳細情報:序文: vueでは、デフォルトページを実装し、di...

VueのkeepAliveコンポーネントの機能と使い方の詳細な説明

序文面接中、多くの面接官は「keep-alive が何をするのか知っていますか?」と質問する際に V...

Linux スワップ パーティション (詳細説明)

目次リナックス1. SWAPとは2. swappiness は何を調節しますか? 3. スワップ操作...