通常の {...}
構文では、1つのオブジェクトを作成できます。しかし、多くの場合、複数のユーザーやメニュー項目など、同様のオブジェクトを多数作成する必要があります。
これは、コンストラクタ関数と "new"
演算子を使用して行うことができます。
コンストラクタ関数
コンストラクタ関数は、技術的には通常の関数です。ただし、2つの慣例があります。
- 最初の文字は大文字で命名されます。
"new"
演算子を使用してのみ実行する必要があります。
例えば
function User(name) {
this.name = name;
this.isAdmin = false;
}
let user = new User("Jack");
alert(user.name); // Jack
alert(user.isAdmin); // false
関数が new
で実行されると、次の手順が実行されます。
- 新しい空のオブジェクトが作成され、
this
に割り当てられます。 - 関数本体が実行されます。通常は
this
を変更し、新しいプロパティを追加します。 this
の値が返されます。
言い換えれば、new User(...)
は次のようなことを行います。
function User(name) {
// this = {}; (implicitly)
// add properties to this
this.name = name;
this.isAdmin = false;
// return this; (implicitly)
}
そのため、let user = new User("Jack")
は、次と同じ結果になります。
let user = {
name: "Jack",
isAdmin: false
};
これで、他のユーザーを作成したい場合は、new User("Ann")
、new User("Alice")
などを呼び出すことができます。毎回リテラルを使用するよりもはるかに短く、読みやすくなります。
それがコンストラクタの主な目的です。再利用可能なオブジェクト作成コードを実装することです。
もう一度注意してください。技術的には、どの関数(アロー関数を除く。this
を持たないため)もコンストラクタとして使用できます。 new
で実行でき、上記のアルゴリズムを実行します。「最初の文字は大文字」は、関数が new
で実行されることを明確にするための一般的な合意です。
単一の複雑なオブジェクトの作成に関するコードが多数ある場合は、次のように、すぐに呼び出されるコンストラクタ関数でラップできます。
// create a function and immediately call it with new
let user = new function() {
this.name = "John";
this.isAdmin = false;
// ...other code for user creation
// maybe complex logic and statements
// local variables etc
};
このコンストラクタは、どこにも保存されずに作成されて呼び出されるだけなので、再び呼び出すことはできません。そのため、このトリックは、将来再利用することなく、単一のオブジェクトを構築するコードをカプセル化することを目的としています。
コンストラクタモードテスト:new.target
このセクションの構文はめったに使用されません。すべてを知りたい場合を除き、スキップしてください。
関数内では、特別な new.target
プロパティを使用して、new
を使用して呼び出されたか、使用せずに呼び出されたかを確認できます。
通常の呼び出しでは未定義で、new
で呼び出された場合は関数と等しくなります。
function User() {
alert(new.target);
}
// without "new":
User(); // undefined
// with "new":
new User(); // function User { ... }
これは、関数内で new
を使用して「コンストラクタモード」で呼び出されたか、使用せずに「通常モード」で呼び出されたかを知るために使用できます。
次のように、new
と通常の呼び出しの両方で同じことを行うこともできます。
function User(name) {
if (!new.target) { // if you run me without new
return new User(name); // ...I will add new for you
}
this.name = name;
}
let john = User("John"); // redirects call to new User
alert(john.name); // John
このアプローチは、ライブラリで構文をより柔軟にするために使用されることがあります。そのため、人々は new
の有無にかかわらず関数を呼び出すことができ、それでも機能します。
ただし、new
を省略すると、何が起こっているのかが少しわかりにくくなるため、おそらくどこでも使用するのに適しているわけではありません。 new
を使用すると、新しいオブジェクトが作成されていることがわかります。
コンストラクタからの戻り値
通常、コンストラクタには return
文がありません。それらのタスクは、必要なすべてのものを this
に書き込むことであり、それが自動的に結果になります。
ただし、return
文がある場合は、ルールは簡単です。
return
がオブジェクトで呼び出された場合、this
の代わりにオブジェクトが返されます。return
がプリミティブで呼び出された場合、無視されます。
言い換えれば、オブジェクトを含む return
はそのオブジェクトを返し、他のすべての場合では this
が返されます。
たとえば、ここでは return
はオブジェクトを返すことによって this
をオーバーライドします。
function BigUser() {
this.name = "John";
return { name: "Godzilla" }; // <-- returns this object
}
alert( new BigUser().name ); // Godzilla, got that object
そして、空の return
の例を次に示します(または、その後にプリミティブを配置することもできます。問題ありません)。
function SmallUser() {
this.name = "John";
return; // <-- returns this
}
alert( new SmallUser().name ); // John
通常、コンストラクタには return
文がありません。ここでは、主に完全を期すために、オブジェクトを返す特別な動作について説明します。
ちなみに、new
の後の括弧は省略できます。
let user = new User; // <-- no parentheses
// same as
let user = new User();
ここで括弧を省略することは「良いスタイル」とは見なされませんが、構文は仕様で許可されています。
コンストラクタのメソッド
コンストラクタ関数を使用してオブジェクトを作成すると、非常に柔軟になります。コンストラクタ関数には、オブジェクトの作成方法とオブジェクトに配置する内容を定義するパラメータを含めることができます。
もちろん、this
にプロパティだけでなく、メソッドも追加できます。
たとえば、以下の new User(name)
は、指定された name
とメソッド sayHi
を持つオブジェクトを作成します。
function User(name) {
this.name = name;
this.sayHi = function() {
alert( "My name is: " + this.name );
};
}
let john = new User("John");
john.sayHi(); // My name is: John
/*
john = {
name: "John",
sayHi: function() { ... }
}
*/
複雑なオブジェクトを作成するには、後で説明するより高度な構文であるクラスがあります。
まとめ
- コンストラクタ関数、または略してコンストラクタは、通常の関数ですが、最初の文字は大文字で命名するという一般的な合意があります。
- コンストラクタ関数は、
new
を使用してのみ呼び出す必要があります。このような呼び出しは、開始時に空のthis
を作成し、最後に設定されたものを返すことを意味します。
コンストラクタ関数を使用して、複数の同様のオブジェクトを作成できます。
JavaScriptは、日付の Date
、セットの Set
など、今後学習する予定の多くの組み込み言語オブジェクトのコンストラクタ関数を備えています。
コメント
<code>
タグを使用し、複数行の場合は<pre>
タグで囲み、10行を超える場合はサンドボックス(plnkr、jsbin、codepen…)を使用してください。