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 タグの属性と使用法

推薦する

mysql8.0.11 winx64 インストールと設定のチュートリアル

mysql 8.0.11 winx64のインストールチュートリアルは以下のように記録され、みんなと共...

HTML入力で値が変更されたときにリスナーイベントを追加することの簡単な分析

達成される効果多くの場合、入力ボックスの値の変化をリアルタイムで監視し、ブラウザを誘導してウェブサイ...

HTMLの基本構文は、HTMLを学び始めたばかりの人にとって便利です。

1.1 一般的なマーキング一般的なタグは開始タグと終了タグで構成されます。構文は次のとおりです: ...

CSS スタイルが機能しない (史上最も完全な解決策の概要)

ページを作成するときに、記述した CSS スタイルが有効にならないことがあります。この現象にはさまざ...

CSS を使用してテクスチャ付きグラデーション背景画像を記述するためのサンプル コード

プロジェクト内のページの長さはおよそ2000px以上あり、背景画像にはテクスチャやグラデーションがあ...

MySQLはmysqldump+binlogを使用して、削除されたデータベースの原理分析を完全に復元します。

1. 概要MySQL データベースの日常的な操作とメンテナンスにおいて、ユーザーが誤ってデータを削...

MySQL をベースにしたシンプルな検索エンジンを実装する

目次MySQL ベースの検索エンジンの実装1. ngram全文パーサー2. 全文インデックスを作成す...

vueはel-tableの列幅の適応を完璧に実現します

目次背景技術的ソリューション具体的な実装要約する背景Element UI は、PC で人気の Vue...

ミニプログラム開発ツールのソースコードからの基本実装の分析

目次ミニプログラム開発者ツールのソースコードを表示する方法ミニプログラムアーキテクチャ設計1. ミニ...

MySQL ALTERコマンドの知識ポイントのまとめ

テーブル名を変更したり、テーブル フィールドを変更したりする必要がある場合は、 MySQL ALTE...

MySql 8.0.11 のインストールと設定のチュートリアル

公式ウェブサイトアドレス: https://dev.mysql.com/downloads/mysq...

nginx で複数の仮想ホストを設定する方法の例

nginx で仮想ホスト vhost を設定すると非常に便利です。 nginx設定ファイルnginx...

NodeとPythonの双方向通信実装コード

目次プロセスコミュニケーションプロセス間の双方向通信問題要約するサードパーティのデータ サプライヤー...

CentOS 6.4 MySQL 5.7.18 のインストールと設定方法のグラフィックチュートリアル

Centos6.4 で mysql5.7.18 をインストールするための具体的な手順が全員に共有され...

ハイパーリンクを使用してリンクファイルを開く HTML 方式の紹介

a および href 属性 HTML では、英語ではアンカーと呼ばれるハイパーリンクを表すために &...