#インスタンスオブジェクトと新しいコマンド

JavaScript 言語には強力なオブジェクト指向プログラミング機能があります。この章では、JavaScript オブジェクト指向プログラミングの基本知識を紹介します。

オブジェクトは何ですか?

オブジェクト指向プログラミング (OOP) は、現在の主流のプログラミング パラダイムです。現実世界のさまざまな複雑な関係をオブジェクトに抽象化し、オブジェクト間の分業と協力によって現実世界のシミュレーションを完成させます。

各オブジェクトは明確な役割分担を持つ機能センターであり、情報の受信、データの処理、情報の送信などのタスクを実行できます。オブジェクトは、継承メカニズムを通じて再利用およびカスタマイズできます。そのため、オブジェクト指向プログラミングは、一連の関数や命令から構成される従来の手続き型プログラミング(手続き型プログラミング)に比べ、柔軟性、コードの再利用性、モジュール性の高さなどの特徴があり、保守や開発が容易です。大規模なソフトウェア プロジェクトに適しています。

では、「オブジェクト」とは一体何なのでしょうか?私たちはそれを 2 つのレベルから理解します。

**(1) オブジェクトは、単一の物理オブジェクトを抽象化したものです。 **

本、車、人がオブジェクトになる可能性があり、データベース、Web ページ、リモート サーバー接続もオブジェクトになる可能性があります。物理的オブジェクトがオブジェクトに抽象化されると、物理的オブジェクト間の関係がオブジェクト間の関係になり、実際の状況をシミュレートしたり、オブジェクトをプログラムしたりできるようになります。

**(2) オブジェクトは、プロパティとメソッドをカプセル化するコンテナです。 **

プロパティはオブジェクトの状態であり、メソッドはオブジェクトの動作(特定のタスクを実行するための)です。たとえば、動物を「動物」オブジェクトに抽象化し、「属性」を使用して特定の動物を記録し、「メソッド」を使用して動物の特定の行動 (走る、狩り、休むなど) を表現できます。

コンストラクター

オブジェクト指向プログラミングの最初のステップは、オブジェクトを生成することです。前述したように、オブジェクトは単一の物理オブジェクトを抽象化したものです。通常、特定のタイプの物理オブジェクトの共通の特性を表すにはテンプレートが必要であり、オブジェクトはこのテンプレートに基づいて生成されます。

代表的なオブジェクト指向プログラミング言語(C++やJavaなど)には「クラス」という概念があります。いわゆる「クラス」はオブジェクトのテンプレートであり、オブジェクトは「クラス」のインスタンスです。ただし、JavaScript 言語のオブジェクト システムは「クラス」ではなく、コンストラクターとプロトタイプ チェーンに基づいています。

JavaScript 言語は、オブジェクトのテンプレートとしてコンストラクターを使用します。いわゆる「コンストラクター」は、インスタンス オブジェクトを生成するために特別に使用される関数です。これはオブジェクトのテンプレートであり、インスタンス オブジェクトの基本構造を記述します。コンストラクターは、すべて同じ構造を持つ複数のインスタンス オブジェクトを生成できます。

コンストラクターは通常の関数ですが、独自の特徴と使用法があります。

var Vehicle = function () {
  this.price = 1000;
};

上記のコードでは、Vehicle がコンストラクターです。通常の関数と区別するために、コンストラクター名の最初の文字は大文字で表記されます。

コンストラクターには 2 つの特徴があります。

  • this キーワードは関数本体内で使用され、生成されるオブジェクト インスタンスを表します。
  • オブジェクトを生成するときは、new コマンドを使用する必要があります。

まずは「new」コマンドを紹介します。

新しいコマンド

基本的な使い方

new コマンドの機能は、コンストラクターを実行してインスタンス オブジェクトを返すことです。

var Vehicle = function () {
  this.price = 1000;
};

var v = 新しい車両();
v.価格 // 1000

上記のコードは、new コマンドを使用して、コンストラクター Vehicle にインスタンス オブジェクトを生成させ、それを変数 v に保存します。この新しく生成されたインスタンス オブジェクトは、コンストラクター Vehicle から price プロパティを取得します。 new コマンドが実行されると、コンストラクター内の this は新しく生成されたインスタンス オブジェクトを表し、インスタンス オブジェクトが値 1000 の price 属性を持つことを意味します。

「new」コマンドを使用する場合、コンストラクターは必要に応じてパラメーターを受け入れることもできます。

var Vehicle = 関数 (p) {
  this.price = p;
};

var v = 新しい車両(500);

new コマンド自体はコンストラクターを実行できるため、後続のコンストラクターには括弧があってもなくてもかまいません。次の 2 行のコードは同等ですが、これが関数呼び出しであることを示すために、かっこを使用することをお勧めします。

// 推奨の書き方
var v = 新しい車両();
// 非推奨の書き方
var v = 新しい車両。

自然な疑問は、「new」コマンドの使用を忘れてコンストラクターを直接呼び出したらどうなるかということです。

この場合、コンストラクタは通常の関数となり、インスタンスオブジェクトは生成されません。また、後で説明する理由により、「this」はグローバル オブジェクトを表すようになり、予期しない結果が発生します。

var 車両 = 関数 (){
  this.price = 1000;
};

var v = 車両();
v // 未定義
価格 // 1000

上記のコードでは、Vehicle コンストラクターを呼び出すときに、new コマンドを追加するのを忘れていました。その結果、変数 v未定義 になり、price プロパティはグローバル変数になります。したがって、「new」コマンドを使用せずにコンストラクターを直接呼び出さないように細心の注意を払う必要があります。

コンストラクターが必ず new コマンドで使用されるようにするための 1 つの解決策は、コンストラクター内で strict モードを使用することです。つまり、最初の行に use strict を追加します。この場合、「new」コマンドの使用を忘れてコンストラクターを直接呼び出すと、エラーが報告されます。

関数 Fubar(foo, bar){
  '厳密を使用';
  this._foo = foo;
  this._bar = バー;
}

フバール()
// TypeError: 未定義のプロパティ '_foo' を設定できません

上記のコードの Fubar はコンストラクターであり、use strict コマンドは関数が strict モードで実行されることを保証します。厳密モードでは、関数内の this はグローバル オブジェクトを指すことができず、デフォルトで unknown になるため、new なしで呼び出すとエラーが報告されます (JavaScript では unknown に属性を追加することはできません)。

別の解決策は、「new」コマンドがコンストラクターで使用されているかどうかを内部的に判断し、使用されていないことが判明した場合は、インスタンス オブジェクトを直接返します。

関数 Fubar(foo, bar) {
  if (!(Fubar のこのインスタンス)) {
    新しい Fubar(foo, bar) を返します。
  }

  this._foo = foo;
  this._bar = バー;
}

Fubar(1, 2)._foo // 1
(new Fubar(1, 2))._foo // 1

上記のコードのコンストラクターは、「new」コマンドが追加されているかどうかに関係なく、同じ結果を取得します。

新しいコマンドの原理

new コマンドを使用すると、それに続く関数は次の手順を順番に実行します。

  1. 返却するオブジェクトインスタンスとして空のオブジェクトを作成します。
  2. この空のオブジェクトのプロトタイプをコンストラクターの prototype 属性に指定します。
  3. この空のオブジェクトを関数内の this キーワードに割り当てます。
  4. コンストラクター内のコードの実行を開始します。

言い換えると、コンストラクター内では、「this」は新しく生成された空のオブジェクトを参照し、「this」に対するすべての操作はこの空のオブジェクトに対して行われます。コンストラクターが「コンストラクター」と呼ばれる理由は、この関数の目的が空のオブジェクト (つまり、「this」オブジェクト) を操作し、それを必要なものに「構築」することであることを意味します。

コンストラクター内に return ステートメントがあり、return の後にオブジェクトが続く場合、new コマンドは return ステートメントで指定されたオブジェクトを返します。それ以外の場合、return ステートメントは無視されます。 「this」オブジェクトが返されます。

var Vehicle = function () {
  this.price = 1000;
  1000 を返します。
};

(新しい車両()) === 1000
// 間違い

上記のコードでは、コンストラクター Vehiclereturn ステートメントは値を返します。この時点で、new コマンドは return ステートメントを無視し、「構築された」 this オブジェクトを返します。

ただし、「return」ステートメントが「this」に関係のない新しいオブジェクトを返す場合、「new」コマンドは「this」オブジェクトの代わりに新しいオブジェクトを返します。この点は特に注意が必要です。

var 車両 = 関数 (){
  this.price = 1000;
  return { 価格: 2000 };
};

(新車()).価格
// 2000

上記のコードでは、コンストラクター Vehiclereturn ステートメントは新しいオブジェクトを返します。 「new」コマンドは、「this」オブジェクトではなく、このオブジェクトを返します。

一方、通常の関数 (内部に this キーワードが含まれていない関数) で new コマンドを使用すると、空のオブジェクトが返されます。

関数 getMessage() {
  「これはメッセージです」を返します。
}

var msg = 新しい getMessage();

msg // {}
typeof msg // "オブジェクト"

上記のコードでは、getMessage は文字列を返す通常の関数です。これに対して「new」コマンドを使用すると、空のオブジェクトが生成されます。これは、new コマンドが常にオブジェクト (インスタンス オブジェクトまたは return ステートメントで指定されたオブジェクト) を返すためです。この例では、「return」ステートメントは文字列を返すため、「new」コマンドはこのステートメントを無視します。

newコマンドの内部処理を簡略化すると以下のコードで表すことができます。

function _new(/* コンストラクター */ コンストラクター, /* コンストラクターのパラメーター */ params) {
  //引数オブジェクトを配列に変換します
  var args = [].slice.call(arguments);
  // コンストラクターを取り出します
  var コンストラクター = args.shift();
  //空のオブジェクトを作成し、コンストラクターのプロトタイププロパティを継承します
  var context = Object.create(constructor.prototype);
  //コンストラクタを実行
  var result =constructor.apply(context, args);
  // 返された結果がオブジェクトの場合は直接返し、それ以外の場合はコンテキスト オブジェクトを返します
  return (結果のタイプ === 'オブジェクト' && 結果 != null) 結果 : コンテキスト;
}

// 実例
varactor = _new(人, '张三', 28);

新しい.ターゲット

new.target 属性は関数内で使用できます。現在の関数が new コマンドによって呼び出された場合、new.target は現在の関数を指します。それ以外の場合、それは 未定義 になります。

関数 f() {
  console.log(new.target === f);
}

f() // false
new f() // true

この属性を使用すると、関数の呼び出し時に「new」コマンドが使用されるかどうかを決定できます。

関数 f() {
  if (!new.target) {
    throw new Error('新しいコマンドを使用して呼び出してください!');
  }
  // ...
}

f() // キャッチされないエラー: 新しいコマンドを使用して呼び出してください。

上記のコードでは、new コマンドを使用せずにコンストラクター f を呼び出すと、エラーがスローされます。

Object.create() はインスタンス オブジェクトを作成します

コンストラクターはテンプレートとして機能し、インスタンス オブジェクトを生成できます。ただし、コンストラクターを取得できず、既存のオブジェクトしか取得できない場合があります。この既存のオブジェクトをテンプレートとして使用して、新しいインスタンス オブジェクトを生成したいと考えています。この場合、Object.create() メソッドを使用できます。

var person1 = {
  名前:「チャン・サン」、
  年齢:38歳、
  挨拶: function() {
    console.log('こんにちは! 私は ' + this.name + '.');
  }
};

var person2 = Object.create(person1);

person2.name // チャン・サン
person2.greeting() // こんにちは、張三です。

上記のコードでは、オブジェクト person1person2 のテンプレートであり、後者は前者のプロパティとメソッドを継承します。

Object.create() の詳細については、以下の関連する章を参照してください。


作者: wangdoc

アドレス: https://wangdoc.com/

ライセンス: クリエイティブ・コモンズ 3.0