#インスタンスオブジェクトと新しいコマンド
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
コマンドを使用すると、それに続く関数は次の手順を順番に実行します。
- 返却するオブジェクトインスタンスとして空のオブジェクトを作成します。
- この空のオブジェクトのプロトタイプをコンストラクターの
prototype
属性に指定します。 - この空のオブジェクトを関数内の
this
キーワードに割り当てます。 - コンストラクター内のコードの実行を開始します。
言い換えると、コンストラクター内では、「this」は新しく生成された空のオブジェクトを参照し、「this」に対するすべての操作はこの空のオブジェクトに対して行われます。コンストラクターが「コンストラクター」と呼ばれる理由は、この関数の目的が空のオブジェクト (つまり、「this」オブジェクト) を操作し、それを必要なものに「構築」することであることを意味します。
コンストラクター内に return
ステートメントがあり、return
の後にオブジェクトが続く場合、new
コマンドは return
ステートメントで指定されたオブジェクトを返します。それ以外の場合、return
ステートメントは無視されます。 「this」オブジェクトが返されます。
var Vehicle = function () {
this.price = 1000;
1000 を返します。
};
(新しい車両()) === 1000
// 間違い
上記のコードでは、コンストラクター Vehicle
の return
ステートメントは値を返します。この時点で、new
コマンドは return
ステートメントを無視し、「構築された」 this
オブジェクトを返します。
ただし、「return」ステートメントが「this」に関係のない新しいオブジェクトを返す場合、「new」コマンドは「this」オブジェクトの代わりに新しいオブジェクトを返します。この点は特に注意が必要です。
var 車両 = 関数 (){
this.price = 1000;
return { 価格: 2000 };
};
(新車()).価格
// 2000
上記のコードでは、コンストラクター Vehicle
の return
ステートメントは新しいオブジェクトを返します。 「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() // こんにちは、張三です。
上記のコードでは、オブジェクト person1
は person2
のテンプレートであり、後者は前者のプロパティとメソッドを継承します。
Object.create()
の詳細については、以下の関連する章を参照してください。
作者: wangdoc
アドレス: https://wangdoc.com/
ライセンス: クリエイティブ・コモンズ 3.0