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

推薦する

Vueはボトムクエリ関数を実装します

この記事では、ボトムクエリ機能を実装するためのVueの具体的なコードを例として紹介します。具体的な内...

ダイナミックな波効果を実現するSVG+CSS3

ベクトル波 <svg viewBox="0 0 560 20" class...

Nginx操作応答ヘッダー情報の実装

前提条件: ヘッダー情報操作をサポートするには、ngx_http_headers_module モジ...

ユニークインデックスの S ロックと X ロックによる MySQL デッドロック ルーチンの理解

「初心者向けソースコードからの MySQL デッドロック問題の理解」では、MySQL ソースコードを...

Vue2.0+ElementUI+PageHelperで実装されたテーブルページング機能

序文最近、いくつかのフロントエンド プロジェクトに取り組んでおり、ページにいくつかのテーブルを表示す...

Linux でユーザーにルート権限を追加する方法の概要

1. ユーザーを追加します。まず、adduser コマンドを使用して共通ユーザーを追加します。コマン...

Ubuntu 19.04 インストール チュートリアル (画像とテキストの手順)

1. 準備1.1 VMware 15 をダウンロードしてインストールするダウンロード リンク: h...

Node.js http モジュールの使用

目次序文ウェブHTTP サーバーファイルサーバー練習する序文Node.js 開発の目的は、JavaS...

div の高さをブラウザの高さに合わせて調整する方法

この古くからある疑問は、数え切れないほどのフロントエンド開発者やバックエンドプログラマーを悩ませてき...

MySQL 5.7.21 解凍版のインストールと設定方法のグラフィックチュートリアル (win10)

MySQL 5.7.21 解凍版のインストールと設定方法は参考までに。具体的な内容は以下のとおりで...

nginx をコンパイルしてインストールした後、スムーズに nginx をアップグレードする方法

nginx をコンパイルしてインストールし、一定期間使用した後、現在のバージョンに脆弱性があることや...

Docker コンテナにおける Patroni の簡単な分析

目次イメージの作成ファイル構造Dockerファイルエントリポイント関数ファイルを生成するイメージを構...

データベースミドルウェアMyCatの紹介

1. Mycatの適用シナリオMycat は幅広いシナリオに合わせて開発されており、新しいユーザーが...

Apache Tika を使用してファイルが破損しているかどうかを検出する方法

Apache Tika は、さまざまな形式のファイルからファイル タイプを検出し、コンテンツを抽出す...

WeChat アプレット計算機の例

WeChatアプレット計算機の例、参考までに、具体的な内容は次のとおりです。インデックス.wxml ...