JSにおけるnewの原理と実装について詳しく話しましょう

JSにおけるnewの原理と実装について詳しく話しましょう

意味

new 演算子は、ユーザー定義のオブジェクト タイプのインスタンス、またはコンストラクターを持つ組み込みオブジェクトのインスタンスを作成します。

オブジェクト インスタンスを作成するには、新しい [コンストラクター] メソッドを使用しますが、コンストラクターが異なると、異なるインスタンスが作成されます。

コンストラクタ本体は異なる

コンストラクタも関数です。唯一の違いは呼び出し方法です。new 演算子で呼び出される関数はすべてコンストラクタであり、new 演算子で呼び出されない関数は通常の関数です。

したがって、コンストラクターにも戻り値がありますが、これにより new の結果が異なります。

戻り値なし

関数 Person(名前) {
  this.name = 名前;
}

obj = new Person("Jalenl"); とします。
コンソールにログ出力します。

明らかに、印刷されているのは{name:'Jalenl'}です

戻りオブジェクト

関数 Person(年齢) {
  this.age = 年齢;
  戻り値: { name: "Jalenl" };
}

obj = new Person(18); とする。
コンソールにログ出力します。

印刷されるのは {name:'Jalenl'} であり、これは return の前のすべての定義が上書きされることを意味します。ここで返されるのはオブジェクトですが、基本型の場合はどうなるでしょうか?

非オブジェクトを返す

関数 Person(年齢) {
  this.age = 年齢;
  1 を返します。
}

obj = new Person(18); とする。
コンソールにログ出力します。

{age:21} を返します。これは戻り値が無効であることを意味し、戻り値がない場合と同じ結果になります。このバインドされた内部属性がなく、基本データ型が返された場合はどうなるでしょうか。

プロパティバインディングなし + 非オブジェクトを返す

関数Person(){
    戻り値 1
}
新しい人()

返される値は、予想どおり、空のオブジェクト {} です。

要約すると、初期結果は、コンストラクターの戻り値がオブジェクト型を返す場合にのみ変更できます。

コンストラクタの型は異なります

コンストラクタは通常の関数である

ECMA-262 第 3 版仕様では、オブジェクト インスタンスを作成するプロセスについて説明しています。

13.2.2 [[構築]]
FunctionオブジェクトFの[[Construct]]プロパティが呼び出されると、次の手順が実行されます。

  1. 新しいネイティブ ECMAScript オブジェクトを作成します。
  2. Result(1)の[[Class]]プロパティを「Object」に設定します。
  3. F のプロトタイプ プロパティの値を取得します。
  4. Result(3)がオブジェクトの場合、Result(1)の[[Prototype]]プロパティをResult(3)に設定します。
  5. Result(3)がオブジェクトでない場合は、15.2.3.1で説明されているように、Result(1)の[[Prototype]]プロパティを元のObjectプロトタイプオブジェクトに設定します。
  6. Fの[[Call]]プロパティを呼び出し、Result(1)をthis値として提供し、[[Construct]]に渡された引数リストを引数値として提供します。
  7. Type(Result(6))がObjectの場合はResult(6)を返します。
  8. 結果(1)を返します。

総括する:

  1. メモリ内に新しいオブジェクトを作成します。
  2. この新しいオブジェクト内の [[Prototype]] プロパティは、コンストラクター関数の prototype プロパティに割り当てられます。
  3. コンストラクター内の this は新しいオブジェクトに割り当てられます (つまり、 this は新しいオブジェクトを指します)。
  4. コンストラクター内のコードを実行します (新しいオブジェクトにプロパティを追加します)。
  5. コンストラクターがオブジェクトを返す場合はそのオブジェクトが返されます。それ以外の場合は、新しく作成されたオブジェクト (空のオブジェクト) が返されます。

5 番目のステップでは、異なるコンストラクターが異なる新しい結果につながる理由をすでに説明しました。

以下はMDNからの説明です。

コード new Foo(…) が実行されると、次のことが起こります。

  1. Foo.prototype から継承する新しいオブジェクトが作成されます。
  2. 指定された引数を使用してコンストラクター Foo を呼び出し、これを新しく作成されたオブジェクトにバインドします。 new Foo は new Foo() と同等です。つまり、引数リストは指定されず、Foo は引数なしで呼び出されます。
  3. コンストラクターによって返されるオブジェクトは、新しい式の結果です。コンストラクターが明示的にオブジェクトを返さない場合は、手順 1 で作成されたオブジェクトが使用されます。 (通常、コンストラクターは値を返しませんが、ユーザーは通常のオブジェクト作成手順をオーバーライドするためにオブジェクトを積極的に返すことを選択できます)

コンストラクタは矢印関数である

通常の関数が作成されると、エンジンは特定のルールに従って、この関数のプロトタイプ プロパティ (プロトタイプ オブジェクトを指す) を作成します。デフォルトでは、すべてのプロトタイプ オブジェクトは、関連付けられているコンストラクターを指すコンストラクターと呼ばれるプロパティを自動的に取得します。

関数Person(){
    18歳未満
}
人物プロトタイプ
/**
{
    コンストラクタ: ƒFoo()
    __proto__: オブジェクト
}
**/

矢印関数を作成する場合、エンジンはそれのプロトタイプ プロパティを作成しません。矢印関数には new を呼び出すコンストラクターがないため、new を使用して矢印関数を呼び出すとエラーが発生します。

定数 Person = ()=>{}
new Person() // TypeError: Foo はコンストラクタではありません

手書きの新着

まとめると、new の動作原理を理解した後は、自分でロープロファイルバージョンの new を実装できます。実装の鍵は次のとおりです。

  1. インスタンスがプライベート プロパティにアクセスできるようにします。
  2. インスタンスがコンストラクター プロトタイプ (constructor.prototype) が配置されているプロトタイプ チェーン上のプロパティにアクセスできるようにします。
  3. コンストラクターによって返される最終結果は参照データ型です。
関数_new(コンストラクタ、...引数) {
    // コンストラクタ型の法的判断 if(typeof コンストラクタ !== 'function') {
      throw new Error('コンストラクタは関数である必要があります');
    }
    // 新しい空のオブジェクトインスタンスを作成します。let obj = new Object();
    // コンストラクターのプロトタイプを新しく作成されたオブジェクトインスタンスにバインドします。obj.__proto__ = Object.create(constructor.prototype);
    // コンストラクターを呼び出して戻り値を決定します。let res =constructor.apply(obj, args);
    isObject = typeof res === 'object' && res !== null とします。
    isFunction = typeof res === 'function' とします。
    // 戻り値があり、それがオブジェクト型である場合は、それを戻り値として使用し、それ以外の場合は以前に作成されたオブジェクトを返します。 return isObject || isFunction ? res : obj;
};

この目立たない new 実装は、カスタム クラスのインスタンスを作成するために使用できますが、組み込みオブジェクトはサポートされません。結局のところ、new は演算子であり、基礎となる実装はより複雑です。

要約する

JS における new の原理と実装に関するこの記事はこれで終わりです。JS における new の原理と実装に関するより関連性の高いコンテンツについては、123WORDPRESS.COM で以前の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM を応援していただければ幸いです。

以下もご興味があるかもしれません:
  • JS の new 関数の詳細な説明
  • JavaScript の new 演算子の原理と例の詳細な説明
  • JavaScript で new を実装する 2 つの方法の調査
  • JavaScript の new 演算子を自分で実装する方法
  • Js における new 演算子の役割の詳細な説明
  • c# Newtonsoft.Json の一般的なメソッドの概要
  • C# Newtonsoft.Json は、複数のネストされた JSON を解析してデシリアライズする例です。
  • c# Newtonsoft.Json パッケージ操作の追加
  • JavaScriptの新しいコマンド
  • JS での new の手書き実装

<<:  ウェブデザインにおけるポップアップウィンドウとフローティングレイヤーのデザイン

>>:  ins タグと del タグの属性と使用法

推薦する

HTML(CSSスタイル仕様)を読む必要があります

CSS スタイル仕様1. クラスセレクター2. タグセレクター3. IDセレクター4. CSSスタイ...

弾幕効果を実現するためのjQuery

この記事では、弾幕効果を実現するためのjQueryの具体的なコードを参考までに共有します。具体的な内...

カルーセル効果を実現するためのネイティブJavaScript+CSS

この記事では、参考までに、カルーセル効果の具体的なコードをJavaScript+CSSを使用して実装...

VMware 仮想マシンのインストール Linux システムのグラフィック チュートリアル

この記事では、LinuxシステムのVMwareインストールの具体的な手順を参考までに紹介します。具体...

Vue router-viewとrouter-linkの実装原理

使用 <div id="アプリ"> <router-link ...

HTMLにリンクを挿入する方法

各 Web ページには、URL () で識別されるアドレスがあります。通常、Web サイト内でリンク...

CSS変数を使用してスタイルを変更する方法の例

質問js を使用して CSS 疑似クラス スタイルを変更するにはどうすればよいでしょうか?しかし、j...

ServerSocketのデフォルトIPバインディングの実装プロセスの詳細な説明

開発中にサーバーを起動する必要がある場合、ローカルテストではポートを直接書き込み、実際の環境ではバイ...

MySQLのページング制限のパフォーマンス問題についての簡単な説明

MySQL ページング クエリは通常、制限を通じて実装されます。 limit は 1 つまたは 2 ...

Centos8.2 クラウド サーバー環境に Tomcat8.5 をインストールするための詳細なチュートリアル

Tomcatをインストールする前に、まずJDK環境をインストールしてくださいLinux サーバー上で...

React は antd のアップロード コンポーネントを使用してファイル フォーム送信機能を実装します (完全なコード)

私はプロジェクトを実行するために react を使い始めたばかりで、非常に未熟で完全な初心者です。私...

MySQLカスタム関数の原理と使用法の分析

この記事では、例を使用して MySQL カスタム関数の原理と使用方法を説明します。ご参考までに、詳細...

前後の秒、分、時間、日数を取得するMySQLデータベース

現在の時刻を取得します: current_timestamp を選択します。出力: 2016-06-...

HTML ページ ソース コード レイアウトの概要_Powernode Java Academy

HTML ページ ソース コード レイアウトの概要この紹介では、Google のホームページのソー...

Linux での nginx のインストール、展開、使用方法の詳細な説明

目次1. ダウンロード2. 展開3. Nginxログ関連の設定4. ファイルダウンローダーとして n...