ホームページ ウェブフロントエンド jsチュートリアル プロトタイプの継承の詳細な説明は JavaScript_javascript のヒントで説明されています。

プロトタイプの継承の詳細な説明は JavaScript_javascript のヒントで説明されています。

May 16, 2016 pm 04:14 PM
javascript

JavaScript はオブジェクト指向言語です。 JavaScript には、「すべてはオブジェクトである」という非常に古典的な格言があります。オブジェクト指向であるため、カプセル化、継承、ポリモーフィズムというオブジェクト指向の 3 つの主要な特徴があります。ここで説明しているのは JavaScript の継承であり、他の 2 つについては後ほど説明します。

JavaScript の継承は C の継承とは異なります。C の継承はクラスに基づいていますが、JavaScript の継承はプロトタイプに基づいています。

ここで問題が起こります。

プロトタイプとは何ですか?プロトタイプについては、オブジェクトのプロパティとメソッドも保存する C のクラスを参照できます。たとえば、単純なオブジェクト

を書いてみましょう。

コードをコピーします コードは次のとおりです:

関数 動物(名前) {
This.name = 名前;
}
Animal.prototype.setName = 関数(名前) {
This.name = 名前;
}
var Animal = new Animal("wangwang");

これは、属性名とメソッド setName を持つオブジェクト Animal であることがわかります。メソッドの追加など、プロトタイプが変更されると、オブジェクトのすべてのインスタンスがこのメソッドを共有することに注意してください。たとえば

コードをコピーします コードは次のとおりです:

関数 動物(名前) {
This.name = 名前;
}
var Animal = new Animal("wangwang");

現時点では、animal には name 属性のみがあります。一文を加えるなら、

コードをコピーします コードは次のとおりです:

Animal.prototype.setName = 関数(名前) {
This.name = 名前;
}

この時点で、animal にも setName メソッドが追加されます。

このコピーを継承します - 空のオブジェクトから開始します。JS の基本的な型の中にオブジェクトと呼ばれるものがあり、その最も基本的なインスタンスは空のオブジェクト、つまり new Object を直接呼び出すことによって生成されるインスタンスであることがわかっています。 ()、またはリテラル { } を使用して宣言されます。空のオブジェクトは、事前定義されたプロパティとメソッドのみを備えた「クリーン オブジェクト」であり、他のすべてのオブジェクトは空のオブジェクトを継承するため、すべてのオブジェクトがこれらの事前定義されたプロパティとメソッドを持ちます。プロトタイプは実際にはオブジェクト インスタンスです。プロトタイプの意味は、コンストラクターにプロトタイプ オブジェクト A がある場合、コンストラクターによって作成されたインスタンスは A からコピーされる必要があることです。インスタンスはオブジェクト A からコピーされるため、インスタンスは A のプロパティ、メソッド、およびその他のプロパティをすべて継承する必要があります。では、レプリケーションはどのように実現されるのでしょうか?方法 1: 構築のコピー インスタンスが構築されるたびに、インスタンスはプロトタイプからコピーされ、新しいインスタンスとプロトタイプは同じメモリ空間を占有します。これにより、obj1 と obj2 はプロトタイプと「完全に一致」しますが、メモリ空間の消費量が急速に増加するため、非常に不経済でもあります。写真に示すように:


方法 2: コピーオンライト この戦略は、システムに対する一貫したトリックであるコピーオンライトから生まれています。この種の欺瞞の典型的な例は、書き込み時に常にメモリ領域がコピーされるオペレーティング システムのダイナミック リンク ライブラリ (DDL) です。写真に示すように:


obj1 と obj2 がプロトタイプと等しいことをシステムに示す必要があるだけです。そのため、読み取るときは、プロトタイプを読み取るための指示に従うだけで済みます。オブジェクト (obj2 など) のプロパティを記述する必要がある場合は、プロトタイプ イメージをコピーし、今後の操作をこのイメージに向けます。写真に示すように:


この方法の利点は、インスタンスの作成時や属性の読み取り時に大量のメモリ オーバーヘッドが必要ないことです。初回書き込み時にメモリを割り当てるためにコードを使用するだけで、コードとメモリのオーバーヘッドが発生します。 。しかし、イメージへのアクセス効率はプロトタイプへのアクセスと同じであるため、そのようなオーバーヘッドはもうありません。ただし、書き込み操作を頻繁に実行するシステムの場合、この方法は前の方法ほど経済的ではありません。方法 3: 読み取りトラバーサル この方法では、レプリケーションの粒度がプロトタイプからメンバーに変更されます。このメソッドの特徴は、インスタンスのメンバーを書き込むときのみ、メンバー情報をインスタンスイメージにコピーすることです。たとえば (obj2.value=10) のようなオブジェクト属性を書き込むと、value という名前の属性値が生成され、obj2 オブジェクトのメンバー リストに配置されます。写真を見てください:

obj2 は依然としてプロトタイプを指す参照であり、操作中にプロトタイプと同じサイズのオブジェクト インスタンスが作成されないことがわかります。このようにして、書き込み操作によって大量のメモリ割り当てが発生しないため、メモリの使用量が節約されます。違いは、obj2 (およびすべてのオブジェクト インスタンス) がメンバー リストを維持する必要があることです。このメンバー リストは 2 つのルールに従います。 読み取り時に最初にアクセスされることが保証されます。 オブジェクトに属性が指定されていない場合は、プロトタイプが空になるか属性が見つかるまで、オブジェクトのプロトタイプ チェーン全体を走査しようとします。プロトタイプチェーンについては後で説明します。明らかに、3 つの方法の中で読み取りトラバーサルのパフォーマンスが最も優れています。したがって、JavaScript のプロトタイプの継承は読み取りトラバーサルです。コンストラクター C に慣れている人は、トップ オブジェクトのコードを読んだ後、間違いなく混乱するでしょう。結局のところ、class キーワードがない方が理解しやすいのですが、function キーワードは別のキーワードです。しかし、コンストラクターについてはどうでしょうか?実はJavaScriptにも同様のコンストラクターがありますが、これをコンストラクターと呼びます。 new 演算子を使用する場合、コンストラクターが実際に呼び出され、これがオブジェクトにバインドされます。たとえば、次のコードを使用します

コードをコピーします コードは次のとおりです:

var Animal = Animal("wangwang");

動物は未定義になります。戻り値がないのは当然未定義だという人もいるでしょう。次に、Animal のオブジェクト定義を変更すると:

コードをコピーします コードは次のとおりです:

関数 動物(名前) {
This.name = 名前;
これを返してください;
}

今何の動物だと思いますか?
このとき、動物はウィンドウになります。異なるのは、ウィンドウが拡張されて名前属性を持つことです。これは、指定されていない場合、デフォルトで最上位変数である window が使用されるためです。 new キーワードを呼び出すことによってのみ、コンストラクターを正しく呼び出すことができます。では、ユーザーが新しいキーワードを見逃さないようにするにはどうすればよいでしょうか?いくつかの小さな変更を加えることができます:

コードをコピーします コードは次のとおりです:

関数 動物(名前) {
If(!(Animal のこのインスタンス)) {
新しい動物(名前)を返します
}
This.name = 名前;
}

こうすることで確実に対処できます。コンストラクターは、インスタンスがどのオブジェクトに属しているかを示すためにも使用されます。 instanceofを使って判断することもできますが、instanceofは継承時に先祖オブジェクトと実オブジェクトの両方に対してtrueを返すため、適切ではありません。コンストラクターが new で呼び出される場合、デフォルトでは現在のオブジェクトを指します。

コードをコピーします コードは次のとおりです:

console.log(Animal.prototype.constructor === Animal); // true

別の考え方もできます。関数が初期化されるとき、プロトタイプにはまったく値がありません。実装は次のロジックになる可能性があります。

//__proto__ を関数の組み込みメンバーとして設定し、get_prototyoe() がそのメソッドです

コードをコピーします コードは次のとおりです:

var __proto__ = null;
関数 get_prototype() {
If(!__proto__) {
__proto__ = 新しいオブジェクト();
__proto__.constructor = this;
}
__proto__ を返します;
}

この利点は、関数が宣言されるたびにオブジェクト インスタンスを作成する必要がなくなり、オーバーヘッドが節約されることです。コンストラクターは変更できますが、これについては後で説明します。プロトタイプベースの継承 継承が何であるかは誰もがほぼ知っていると思うので、IQ の下限をひけらかすつもりはありません。

JS 継承にはいくつかのタイプがあります。ここでは 2 つのタイプを紹介します

1. 方法 1 この方法は最も一般的に使用されており、セキュリティが優れています。まず 2 つのオブジェクトを定義しましょう

コードをコピーします コードは次のとおりです:

関数 動物(名前) {
This.name = 名前;
}
関数 犬(年齢) {
This.age = 年齢;
}
var Dog = 新しい Dog(2);

継承の構築は非常に簡単で、子オブジェクトのプロトタイプを親オブジェクトのインスタンスにポイントします (これはオブジェクトではなくインスタンスであることに注意してください)

コードをコピーします コードは次のとおりです:

Dog.prototype = new Animal("wangwang");

この時点で、犬には名前と年齢という 2 つの属性が与えられます。そして、犬にinstanceof演算子

を使用すると、

コードをコピーします コードは次のとおりです:

console.log(動物の犬のインスタンス) // true
; console.log(犬のインスタンス) // false

このようにして継承が行われますが、小さな問題があります

コードをコピーします コードは次のとおりです:

console.log(Dog.prototype.constructor === Animal) // true
; console.log(Dog.prototype.constructor === 犬) // false

コンストラクターが指すオブジェクトが変更されていることがわかりますが、これでは新しいインスタンスが誰に属するかを判断できません。したがって、次の文を追加できます:

コードをコピーします コードは次のとおりです:

Dog.prototype.constructor = 犬;

もう一度見てみましょう:

コードをコピーします コードは次のとおりです:

console.log(動物の犬のインスタンス) // false
; console.log(犬のインスタンス) // true
;

完了。このメソッドはプロトタイプ チェーンのメンテナンスの一部であり、以下で詳しく説明します。 2. 方法 2 この方法には長所と短所がありますが、短所が長所を上回ります。まずはコードを見てみましょう

コードをコピーします コードは次のとおりです:

function Animal(name) {
This.name = 名前;
}
Animal.prototype.setName = 関数(名前) {
This.name = 名前;
}
関数 犬(年齢) {
This.age = 年齢;
}
Dog.prototype = Animal.prototype;

これによりプロトタイプのコピーが実現されます。

この方法の利点は、(方法 1 と比較して) オブジェクトをインスタンス化する必要がないため、リソースが節約されることです。上記と同じ問題に加えて、コンストラクターは親オブジェクトを指し、親オブジェクトのプロトタイプによって宣言されたプロパティとメソッドしかコピーできないという欠点も明らかです。つまり、上記のコードでは、Animal オブジェクトの name 属性はコピーできませんが、setName メソッドはコピーできます。最も致命的なのは、子オブジェクトのプロトタイプを変更すると、親オブジェクトのプロトタイプに影響が及ぶことです。つまり、両方のオブジェクトによって宣言されたインスタンスが影響を受けることになります。したがって、この方法はお勧めできません。

プロトタイプチェーン

継承を書いたことがある人なら誰でも、継承は複数のレベルで継承できることを知っています。 JS では、これはプロトタイプ チェーンを構成します。プロトタイプチェーンについては上で何度も言及しましたが、プロトタイプチェーンとは何でしょうか?インスタンスには少なくとも、JavaScript のオブジェクト システムの基礎であるプロトタイプを指す proto 属性が必要です。ただし、このプロパティは目に見えません。コンストラクターのプロトタイプで構成される「コンストラクター プロトタイプ チェーン」(通常、「プロトタイプ チェーン」と呼ばれます) と区別するために、これを「内部プロトタイプ チェーン」と呼びます。まず、上記のコードに従って単純な継承関係を構築しましょう:

コードをコピーします コードは次のとおりです:

関数 動物(名前) {
This.name = 名前;
}
関数 犬(年齢) {
This.age = 年齢;
}
var Animal = new Animal("wangwang");
Dog.prototype = 動物;
var Dog = 新しい Dog(2);

前述したように、すべてのオブジェクトは空のオブジェクトを継承します。したがって、プロトタイプチェーンを構築しました:


子オブジェクトのプロトタイプが親オブジェクトのインスタンスを指しており、コンストラクター プロトタイプ チェーンを形成していることがわかります。子インスタンスの内部プロト オブジェクトも親オブジェクトのインスタンスを指し、内部プロトタイプ チェーンを形成します。特定の属性を見つける必要がある場合、コードは

に似ています。

コードをコピーします コードは次のとおりです:

function getAttrFromObj(attr, obj) {
If(typeof(obj) === "オブジェクト") {
var proto = obj;
while(プロト) {
If(proto.hasOwnProperty(attr)) {
return proto[attr];
}
proto = proto.__proto__;
}
}
未定義を返します;
}

この例では、dog の name 属性を検索すると、dog のメンバー リストで検索されます。これは、dog のメンバー リストには年齢しか含まれていないため、見つかりません。次に、プロトタイプ チェーン、つまり .proto によって指定されたインスタンスに沿って検索を続けます。つまり、animal では、name 属性を見つけて返します。存在しないプロパティを探していて、animal で見つからない場合は、.proto に沿って検索を続け、空のオブジェクトを見つけます。それが見つからない場合は、.proto に沿って検索を続けます。空のオブジェクトは null を指しており、出口を探しています。

プロトタイプ チェーンのメンテナンス プロトタイプの継承について説明したときに、メソッド 1 を使用して継承を構築する場合、子オブジェクト インスタンスのコンストラクターは親オブジェクトを指します。この利点は、コンストラクター属性を通じてプロトタイプ チェーンにアクセスできることですが、欠点も明らかです。オブジェクト、それが生成するインスタンスはそれ自体を指す必要があります、つまり

コードをコピーします コードは次のとおりです:

(new obj()).prototype.constructor === obj;
その後、プロトタイプ プロパティをオーバーライドすると、サブオブジェクトによって生成されたインスタンスのコンストラクターはそれ自体を指しません。これは構築者の本来の意図に反します。解決策については上で説明しました:

コードをコピーします コードは次のとおりです:
Dog.prototype = new Animal("wangwang");
Dog.prototype.constructor = 犬;

問題ないようです。しかし実際には、これによって新たな問題が発生します。親オブジェクトが見つからず、内部プロトタイプ チェーンの .proto プロパティにアクセスできないため、プロトタイプ チェーンを後戻りできないことがわかります。したがって、SpiderMonkey は改善されたソリューションを提供します。つまり、作成されたオブジェクトに __proto__ という名前の属性を追加します。この属性は、コンストラクターによって使用されるプロトタイプを常に指します。この方法では、コンストラクターを変更しても __proto__ の値に影響を与えないため、コンストラクターの保守が容易になります。

しかし、さらに 2 つの問題があります:

__proto__ はオーバーライド可能です。つまり、使用時に依然としてリスクが存在します

__proto__ は SpiderMonkey の特殊な処理であり、他のエンジン (JScript など) では使用できません。

別の方法もあります。それは、プロトタイプのコンストラクター プロパティを保持し、サブクラスのコンストラクター関数内でインスタンスのコンストラクター プロパティを初期化することです。

コードは次のとおりです: サブオブジェクトを書き換えます

コードをコピーします コードは次のとおりです:
関数 犬(年齢) {
This.constructor = argument.callee;
This.age = 年齢;
}
Dog.prototype = new Animal("wangwang");

このようにして、すべての子オブジェクト インスタンスのコンストラクターはオブジェクトを正しく指し、プロトタイプのコンストラクターは親オブジェクトを指します。この方法は、インスタンスを構築するたびにコンストラクタ属性を書き換える必要があるため、比較的非効率ではありますが、前述の矛盾を効果的に解決できることは間違いありません。 ES5 はこの状況を考慮し、この問題を完全に解決します。コンストラクターにアクセスしたり、外部プロトタイプ チェーンを維持したりすることなく、いつでも Object.getPrototypeOf() を使用してオブジェクトの実際のプロトタイプを取得できます。したがって、前のセクションで説明したようにオブジェクトのプロパティを見つけるには、次のように書き換えることができます:

コードをコピーします コードは次のとおりです:
function getAttrFromObj(attr, obj) {
If(typeof(obj) === "オブジェクト") {
{
を実行します var proto = Object.getPrototypeOf(dog);
If(proto[attr]) {
return proto[attr];
}
}
while(プロト);
}
未定義を返します;
}

もちろん、この方法は ES5 をサポートするブラウザでのみ使用できます。下位互換性のために、以前の方法を考慮する必要があります。より適切な方法は、これら 2 つの方法を統合してカプセル化することです。読者の皆さんはこれが得意だと思いますので、ここでは紹介しません。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

WebSocket と JavaScript を使用してオンライン音声認識システムを実装する方法 WebSocket と JavaScript を使用してオンライン音声認識システムを実装する方法 Dec 17, 2023 pm 02:54 PM

WebSocket と JavaScript を使用してオンライン音声認識システムを実装する方法 はじめに: 技術の継続的な発展により、音声認識技術は人工知能の分野の重要な部分になりました。 WebSocket と JavaScript をベースとしたオンライン音声認識システムは、低遅延、リアルタイム、クロスプラットフォームという特徴があり、広く使用されるソリューションとなっています。この記事では、WebSocket と JavaScript を使用してオンライン音声認識システムを実装する方法を紹介します。

WebSocket と JavaScript: リアルタイム監視システムを実装するための主要テクノロジー WebSocket と JavaScript: リアルタイム監視システムを実装するための主要テクノロジー Dec 17, 2023 pm 05:30 PM

WebSocketとJavaScript:リアルタイム監視システムを実現するためのキーテクノロジー はじめに: インターネット技術の急速な発展に伴い、リアルタイム監視システムは様々な分野で広く利用されています。リアルタイム監視を実現するための重要なテクノロジーの 1 つは、WebSocket と JavaScript の組み合わせです。この記事では、リアルタイム監視システムにおける WebSocket と JavaScript のアプリケーションを紹介し、コード例を示し、その実装原理を詳しく説明します。 1.WebSocketテクノロジー

WebSocketとJavaScriptを使ったオンライン予約システムの実装方法 WebSocketとJavaScriptを使ったオンライン予約システムの実装方法 Dec 17, 2023 am 09:39 AM

WebSocket と JavaScript を使用してオンライン予約システムを実装する方法 今日のデジタル時代では、ますます多くの企業やサービスがオンライン予約機能を提供する必要があります。効率的かつリアルタイムのオンライン予約システムを実装することが重要です。この記事では、WebSocket と JavaScript を使用してオンライン予約システムを実装する方法と、具体的なコード例を紹介します。 1. WebSocket とは何ですか? WebSocket は、単一の TCP 接続における全二重方式です。

JavaScript と WebSocket を使用してリアルタイムのオンライン注文システムを実装する方法 JavaScript と WebSocket を使用してリアルタイムのオンライン注文システムを実装する方法 Dec 17, 2023 pm 12:09 PM

JavaScript と WebSocket を使用してリアルタイム オンライン注文システムを実装する方法の紹介: インターネットの普及とテクノロジーの進歩に伴い、ますます多くのレストランがオンライン注文サービスを提供し始めています。リアルタイムのオンライン注文システムを実装するには、JavaScript と WebSocket テクノロジを使用できます。 WebSocket は、TCP プロトコルをベースとした全二重通信プロトコルで、クライアントとサーバー間のリアルタイム双方向通信を実現します。リアルタイムオンラインオーダーシステムにおいて、ユーザーが料理を選択して注文するとき

JavaScript と WebSocket: 効率的なリアルタイム天気予報システムの構築 JavaScript と WebSocket: 効率的なリアルタイム天気予報システムの構築 Dec 17, 2023 pm 05:13 PM

JavaScript と WebSocket: 効率的なリアルタイム天気予報システムの構築 はじめに: 今日、天気予報の精度は日常生活と意思決定にとって非常に重要です。テクノロジーの発展に伴い、リアルタイムで気象データを取得することで、より正確で信頼性の高い天気予報を提供できるようになりました。この記事では、JavaScript と WebSocket テクノロジを使用して効率的なリアルタイム天気予報システムを構築する方法を学びます。この記事では、具体的なコード例を通じて実装プロセスを説明します。私たちは

簡単な JavaScript チュートリアル: HTTP ステータス コードを取得する方法 簡単な JavaScript チュートリアル: HTTP ステータス コードを取得する方法 Jan 05, 2024 pm 06:08 PM

JavaScript チュートリアル: HTTP ステータス コードを取得する方法、特定のコード例が必要です 序文: Web 開発では、サーバーとのデータ対話が頻繁に発生します。サーバーと通信するとき、多くの場合、返された HTTP ステータス コードを取得して操作が成功したかどうかを判断し、さまざまなステータス コードに基づいて対応する処理を実行する必要があります。この記事では、JavaScript を使用して HTTP ステータス コードを取得する方法を説明し、いくつかの実用的なコード例を示します。 XMLHttpRequestの使用

JavaScriptでinsertBeforeを使用する方法 JavaScriptでinsertBeforeを使用する方法 Nov 24, 2023 am 11:56 AM

使用法: JavaScript では、insertBefore() メソッドを使用して、DOM ツリーに新しいノードを挿入します。このメソッドには、挿入される新しいノードと参照ノード (つまり、新しいノードが挿入されるノード) の 2 つのパラメータが必要です。

JavaScript で HTTP ステータス コードを簡単に取得する方法 JavaScript で HTTP ステータス コードを簡単に取得する方法 Jan 05, 2024 pm 01:37 PM

JavaScript で HTTP ステータス コードを取得する方法の紹介: フロントエンド開発では、バックエンド インターフェイスとの対話を処理する必要があることが多く、HTTP ステータス コードはその非常に重要な部分です。 HTTP ステータス コードを理解して取得すると、インターフェイスから返されたデータをより適切に処理できるようになります。この記事では、JavaScript を使用して HTTP ステータス コードを取得する方法と、具体的なコード例を紹介します。 1. HTTP ステータス コードとは何ですか? HTTP ステータス コードとは、ブラウザがサーバーへのリクエストを開始したときに、サービスが

See all articles