JavaScript プロトタイプとプロトタイプチェーンの詳細

JavaScript プロトタイプとプロトタイプチェーンの詳細

序文:

JavaScript 、多くの場合「プロトタイプベースの言語」として説明されます。各オブジェクトには「プロトタイプ オブジェクト」があり、オブジェクトはプロトタイプをテンプレートとして使用し、プロトタイプからプロパティとメソッドを継承します。プロトタイプ オブジェクトにもプロトタイプがあり、そこからプロパティやメソッドなどが継承されます。この関係は「プロトタイプ チェーン」と呼ばれることが多く、1 つのオブジェクトに他のオブジェクトで定義されたプロパティとメソッドがある理由を説明します。

正確に言うと、これらのプロパティとメソッドは、オブジェクト インスタンス自体ではなく、 Objectコンストラクターのprototypeプロパティで定義されます。

プロトタイプとプロトタイプ チェーンは、次の 4 つの文で明らかになります。

  • 各関数(クラス)はプロパティprototypeを持って生まれ、プロパティ値はインスタンス使用のために現在のクラスのプロパティとメソッドを格納するオブジェクトです(プロトタイプを表示)
  • ブラウザがプロトタイプ用にデフォルトで開くヒープ メモリには、 constructorプロパティがあります。これは、現在のクラス自体を格納します (⚠️注: 自分で開くヒープ メモリには、デフォルトではconstructorプロパティがないため、手動で追加する必要があります) "(コンストラクター)"
  • すべてのオブジェクトには__proto__プロパティがあり、これは現在のインスタンスが属するクラスのプロトタイプを指します (クラスが決定されていない場合はObject.prototypeを指します) (暗黙のプロトタイプ)
  • オブジェクトのプロパティを取得しようとすると、オブジェクト自体にこのプロパティがない場合、暗黙のプロトタイプ __proto__ (つまり、コンストラクターの表示プロトタイプprototype ) でそのプロパティが検索されます。 「(プロトタイプチェーン)」

コンストラクター、プロトタイプ、インスタンスの関係:

constructorにはprototypeオブジェクトがあり、このオブジェクトにはprototype constructorへのポインターが含まれています。また、各instanceはプロトタイプ オブジェクトへの内部ポインター(__proto__)

1. プロトタイプ(明示的なプロトタイプ)

すべての関数にはprototypeプロパティがあります

// コンストラクタ(クラス)
関数 Person(名前){
    this.name = 名前
}
// 新しいインスタンス(オブジェクト)
var person = new Person('南玖')
console.log(person) //Person { name: '南玖' }
console.log(Person.prototype) //コンストラクタ関数のプロトタイプ(クラス)----->object Person.prototype.age = 18 //コンストラクタ関数のプロトタイプ console.log(person.age) // 18


上記では、オブジェクトを指すこの関数Personのプロトタイプを出力しました。このオブジェクトは、コンストラクタを呼び出すことによって作成されたインスタンスのプロトタイプです。

上の図はコンストラクターとインスタンス プロトタイプの関係を示しており、コンストラクターのプロトタイプ プロパティがオブジェクトを指していることがわかります。

インスタンスとそのプロトタイプの関係は何ですか?ここで__proto__属性について言及する必要がある

2. __proto__ (暗黙のプロトタイプ)

上記の4つの文から、これはすべてのJavascriptオブジェクト(nullを除く)が持つプロパティであることがわかります。このプロパティは、オブジェクトのプロトタイプ(つまり、インスタンスプロトタイプ)を指します。

JavaScriptにはクラスの概念がないため、継承に似た方法を実装するために、オブジェクトとプロトタイプは__proto__を介してリンクされ、プロトタイプ チェーンが形成され、オブジェクトはそれに属さないプロパティにアクセスできるようになります。

次に、インスタンスとインスタンスプロトタイプの関係を証明します。

console.log(person.__proto__) //インスタンス (オブジェクト) プロトタイプ ---> オブジェクト console.log(person.__proto__ === Person.prototype) //インスタンスのプロトタイプはコンストラクター関数のプロトタイプと同じです

上の図から、インスタンス オブジェクトとコンストラクターの両方がプロトタイプを指すことができることがわかりますが、プロトタイプはコンストラクターまたはインスタンスを指すことができるのでしょうか?

3. コンストラクター

コンストラクターは複数のインスタンス オブジェクトを作成できるため、プロトタイプにはインスタンスを指す属性はありません。

前の4つの文から、「ブラウザによってプロトタイプ用にデフォルトで割り当てられたヒープメモリにはconstructorプロパティがある」ことがわかっているので、プロトタイプはコンストラクタ関数を指すこともできます。このプロパティは「 constructor 」です。

したがって、次の点を証明できます。

console.log(Person.prototype.constructor) // インスタンスの明示的なプロトタイプのコンストラクタ ƒ Person(name){this.name = name}
console.log(person.__proto__.constructor) //インスタンスの暗黙的なプロトタイプコンストラクター ƒ Person(name){this.name = name}
console.log(person.__proto__.constructor === Person.prototype.constructor) //true インスタンスプロトタイプのコンストラクタは、クラスのコンストラクタと同じです。console.log(Person === Person.prototype.constructor) //true


インスタンス オブジェクトの__proto__どのように生成されますか?
new演算子を使用すると、生成されたインスタンスオブジェクトには__proto__属性があることが分かっています。

関数 Foo() {}
// この関数は Function のインスタンス オブジェクトです // 関数はシンタックス シュガーです // 実際には内部で new Function() を呼び出します


したがって、 newプロセスでは、新しいオブジェクトが__proto__属性とともに追加され、コンストラクターのプロトタイプにリンクされていると言えます。

4. 新しい原則

簡単に言えば、次の 4 つのステップに分けられます。

  • 新しい空のオブジェクトを作成する
  • リンクプロトタイプ
  • これをバインドしてコンストラクタを実行します
  • 新しいオブジェクトを返します
関数myNew() {
// 1. 新しい空のオブジェクトを作成する let obj = {}
// 2. コンストラクタを取得する let con = arguments.__proto__.constructor
// 3. リンクプロトタイプ obj.__proto__ = con.prototype
// 4. これをバインドしてコンストラクタを実行します。let res = con.apply(obj, arguments)
// 5. 新しいオブジェクトを返す return typeof res === 'object' ? res : obj
}

5. プロトタイプチェーン

プロトタイプについて話した後、プロトタイプ チェーンとは何かを見てみましょう。まずは写真を見てみましょう:

この図では、 __proto__で接続されたチェーン関係をプロトタイプチェーンと呼びます。

5.1 プロトタイプチェーンの役割

プロトタイプ チェーンは、 JavaScriptで継承がどのように実装されるかを決定します。プロパティにアクセスする場合、その検索メカニズムは次のようになります。

  • オブジェクトのインスタンス属性にアクセスします。存在する場合は直接返します。存在しない場合は、 __proto__を通じてプロトタイプ オブジェクトで検索します。
  • プロトタイプオブジェクト上で見つかった場合は、それが返されます。見つからない場合は、プロトタイプオブジェクトの__proto__を検索し続けます。
  • Object.prototype が見つかるまで検索を続けます。見つかった場合はそれを返します。見つからない場合はundefined返しますObject.prototype.__proto__は null であるため、これ以上検索しないでください。つまり、Object はすべてのオブジェクトのプロトタイプ チェーンの最上位です。

図から、すべてのオブジェクトは最終的にプロトタイプ チェーンを通じて Object.prototype を見つけることができることがわかります。Object.prototype もオブジェクトですが、このオブジェクトは Object によって作成されるのではなく、エンジン自体が Object.prototype を作成します。したがって、すべてのインスタンスはオブジェクトであると言えますが、すべてのオブジェクトがインスタンスであるとは限りません。

5.2 コンストラクタの __proto__ とは何ですか?

上記のプロトタイプチェーンの説明から、コンストラクター関数の__proto__理解できるはずです。 JavaScriptではすべてがオブジェクトであるため、コンストラクター関数もオブジェクトである必要があり、オブジェクトには__proto__があります。

関数 Person(){}
コンソールログ(Person.__proto__)
console.log(関数プロトタイプ)
console.log(Person.__proto__===Function.prototype) // true


「これは、すべての関数が Function のインスタンスであることも示しています」

このように理解すると、 Function.__proto__ Function.prototype。。。。印刷して見てみましょう

Function.__proto__ === Function.prototype // true


まさにこれが印刷される内容です。 Function.prototypenew Function()によって生成されますか?

答えは「いいえ」です。この機能もエンジン自体によって作成されます。まずエンジンは Object.prototype を作成し、次に Function.prototype を作成し、__proto__ を介してこの 2 つを接続します。これは、let fun = Function.prototype.bind() に prototype プロパティがないのはなぜか、という上記の質問も非常によく説明しています。 Function.prototype はエンジンによって作成されたオブジェクトであるため、エンジンはこのオブジェクトにプロトタイプ プロパティを追加する必要はないと判断します。

6. まとめ

  • Objectはすべてのオブジェクトの親です。すべてのオブジェクトは__proto__を通じてそれを見つけることができます。
  • Functionすべての関数の父です。すべての関数は__proto__を通じてそれを見つけることができます。
  • Function.prototypeObject.prototypeは、エンジンによって作成される 2 つの特殊なオブジェクトです。
  • 上記の 2 つの特殊なオブジェクトを除き、他のオブジェクトはコンストラクターを通じて作成されます。
  • 関数のprototypeはオブジェクト、つまりプロトタイプである。
  • オブジェクトの__proto__はプロトタイプを指します。__ __proto__はオブジェクトとプロトタイプを接続してプロトタイプ チェーンを形成します。

JavaScriptプロトタイプとプロトタイプチェーンの詳細に関するこの記事はこれで終わりです。JavaScript JavaScriptとプロトタイプチェーンの関連コンテンツについては、123WORDPRESS.COM の過去の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • JavaScriptプロトタイプチェーンを理解する
  • JavaScript のプロトタイプとプロトタイプチェーンの詳細な説明
  • JavaScript プロトタイプとプロトタイプチェーンの深い理解
  • Javascript プロトタイプとプロトタイプチェーンをご存知ですか?
  • JavaScriptプロトタイプとプロトタイプチェーンの詳細な説明
  • JavaScript のプロトタイプとプロトタイプ チェーンを理解する

<<:  CSS でレスポンシブ レイアウトを実装する方法

>>:  クラウドデータ移行サービスの観点から見たMySQLの大規模テーブル抽出モードの原理分析

推薦する

MySQL初心者はグループ化や集計クエリの煩わしさから解放されます

目次1. グループクエリの概略図2. groupbyキーワード構文の詳細な説明3. 簡単なグループク...

MySQLデータベースのデータテーブルに関する詳細な基本操作

目次1. 現在のデータベース内のテーブルを表示する2. テーブルを作成する3. 指定されたテーブル構...

ウェブサイトデザインの経験 ウェブサイト構築におけるよくある間違いのまとめ

注意: 計画、設計、開発のいずれの場合でも、これらの間違いは避けなければなりません。 1. ナビゲー...

nestjs における例外フィルター Exceptionfilter の具体的な使用法

Nestjs 例外フィルターといえば、非常に強力な .Net のグローバル フィルターについて触れな...

WeChatアプレット仮想リストの応用例

目次序文仮想リストとは何ですか?デモ効果準備スクリーンの高さとボックスの高さ最適化要約する序文人気の...

ウェブページを白黒に変換します(Google、Firefox、IE、その他のブラウザと互換性があります)

CSSファイルに書き込むコードをコピーコードは次のとおりです。 01.html {グレイスケール(1...

VMWare12 グラフィックチュートリアルで Apple Mac OS X をインストールする

1. はじめに:友人はシステム知識を学びたいと考えており、Apple のラップトップを使用していまし...

MySQL InnoDB row_id 境界オーバーフロー検証方法の手順

背景クラスメートと row_id の境界問題について話し合ったので、ここで詳しく説明します。 Inn...

CentOS 8が利用可能になりました

CentOS 8 が利用可能になりました! CentOS 8 と RedHat Enterprise...

antd+reactプロジェクトをviteに移行するためのソリューションの詳細な説明

Antd+react+webpackは、多くの場合、Reactテクノロジースタックに基づくフロントエ...

Linux リモート管理と sshd サービス検証の知識ポイントの詳細な説明

1. SSHリモート管理SSH の定義SSH (Secure Shell) は、主にキャラクタ イン...

MySQLでページングクエリを実装する方法

SQL ページング クエリ:背景会社のシステムには、構成管理用のプラットフォーム、いわゆる CRUD...

MySQL 5.7 クラスタ構成手順

目次1. サーバーAのmy.cnfファイルを変更する2. サーバーBのmy.cnfファイルを変更する...

HTMLファイルで外部CSSファイルを導入する場合のパスの書き方について簡単にまとめます

1. 外部CSSファイルの基本スタイルをインポートする<link> タグを使用して外部ス...

IE8は優れたエクスペリエンスを提供します: アクティビティ

今日は IE8 ベータ 1 (以下、IE8 と略します) をチラ見しました。IE8 は素晴らしい体験...