概要: このチュートリアルでは、JavaScript コンストラクタ関数と、その new
キーワードを使用してオブジェクトを作成する方法について学習します。
JavaScriptコンストラクタ関数の概要
JavaScript オブジェクトのチュートリアルでは、オブジェクトのリテラル構文を使用して新しいオブジェクトを作成する方法を学習しました。
たとえば、次の例では firstName
と lastName
という 2 つのプロパティを持つ新しい person オブジェクトを作成します。
let person = {
firstName: 'John',
lastName: 'Doe'
};
Code language: JavaScript (javascript)
実際には、person
オブジェクトなどの類似したオブジェクトを数多く作成する必要があります。
これを行うには、カスタムタイプを定義するコンストラクタ関数と、このタイプから複数のオブジェクトを作成する new
演算子を使用します。
技術的には、コンストラクタ関数は次の規約を持つ通常の 関数 です。
- コンストラクタ関数の名前は、
Person
、Document
など、大文字で始まります。 - コンストラクタ関数は、
new
演算子でのみ呼び出す必要があります。
ES6 では、カスタムタイプを定義できる class
キーワードが導入されました。クラスはコンストラクタ関数の構文上の糖衣であり、いくつかの機能強化がされています。
次の例では、Person
というコンストラクタ関数を定義しています。
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
Code language: JavaScript (javascript)
この例では、Person
は名前が大文字の P
で始まるという点以外は通常の関数と同じです。
Person
の新しいインスタンスを作成するには、new
演算子を使用します。
let person = new Person('John','Doe');
Code language: JavaScript (javascript)
基本的に、new
演算子は次のことを行います。
- 新しい空のオブジェクトを作成し、それを
this
変数に割り当てます。 - 引数の
'John'
と'Doe'
をオブジェクトのfirstName
とlastName
プロパティに割り当てます。 this
値を返します。
これは、次の機能と同等です。
function Person(firstName, lastName) {
// this = {};
// add properties to this
this.firstName = firstName;
this.lastName = lastName;
// return this;
}
Code language: JavaScript (javascript)
したがって、次のステートメントは
let person = new Person('John','Doe');
Code language: JavaScript (javascript)
… 次のステートメントと同じ結果を返します。
let person = {
firstName: 'John',
lastName: 'Doe'
};
Code language: JavaScript (javascript)
ただし、コンストラクタ関数 Person
を使用すると、複数の類似したオブジェクトを作成できます。たとえば
let person1 = new Person('Jane','Doe')
let person2 = new Person('James','Smith')
Code language: JavaScript (javascript)
JavaScript コンストラクタ関数にメソッドを追加する
オブジェクトはそのデータを操作するメソッドを持つ場合があります。コンストラクタ関数で作成されたオブジェクトにメソッドを追加するには、this
キーワードを使用できます。たとえば
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
this.getFullName = function () {
return this.firstName + " " + this.lastName;
};
}
Code language: JavaScript (javascript)
これで、新しい Person
オブジェクトを作成し、getFullName()
メソッドを呼び出すことができます。
let person = new Person("John", "Doe");
console.log(person.getFullName());
Code language: JavaScript (javascript)
出力
John Doe
コンストラクタ関数の問題は、Person
のインスタンスを複数作成すると、this.getFullName()
がそれぞれのインスタンスに複製され、メモリ効率が悪いことです。
これを解決するには、カスタムタイプの一部のインスタンスが同じメソッドを共有できるように prototype を使用します。
コンストラクタ関数からの戻り値
通常、コンストラクタ関数は新たに作成されたオブジェクトに設定された this
を暗黙的に返します。ただし、return
ステートメントがある場合は、次の規則があります。
return
がオブジェクトで呼び出された場合、コンストラクタ関数はそのオブジェクトを返します。return
がオブジェクト以外の値で呼び出された場合、それは無視されます。
新しいキーワードなしでコンストラクタ関数を呼び出す
技術的には、次のように new
キーワードを使用せずに、通常の関数のようにコンストラクタ関数を呼び出すことができます。
let person = Person('John','Doe');
Code language: JavaScript (javascript)
この場合、Person
は通常の関数のように実行されます。したがって、Person
関数の内部の this
は person
変数ではなく グローバルオブジェクト に結び付けられます。
firstName
または lastName
プロパティにアクセスしようとすると、エラーが発生します。
console.log(person.firstName);
Code language: CSS (css)
エラー
TypeError: Cannot read property 'firstName' of undefined
Code language: JavaScript (javascript)
同様に、getFullName()
メソッドはグローバルオブジェクトに結び付けられているため、アクセスできません。
person.getFullName();
Code language: CSS (css)
エラー
TypeError: Cannot read property 'getFullName' of undefined
Code language: JavaScript (javascript)
コンストラクタ関数が new
キーワードなしで呼び出されないようにするために、ES6 では new.target
プロパティが導入されました。
コンストラクタ関数が new
キーワードと共に呼び出されると、new.target
は関数の参照を返します。それ以外の場合は、undefined
を返します。
以下は Person
関数にステートメントを追加して new.target
をコンソールに表示するものです。
function Person(firstName, lastName) {
console.log(new.target);
this.firstName = firstName;
this.lastName = lastName;
this.getFullName = function () {
return this.firstName + " " + this.lastName;
};
}
Code language: JavaScript (javascript)
Person
コンストラクタ関数が通常の関数のように呼び出されるので、以下は undefined
を返します。
let person = Person("John", "Doe");
Code language: JavaScript (javascript)
出力
undefined
Code language: JavaScript (javascript)
しかし、以下は new
キーワードで呼び出されるので、Person
関数の参照を返します。
let person = new Person("John", "Doe");
Code language: JavaScript (javascript)
出力
[Function: Person]
Code language: JSON / JSON with Comments (json)
new.target
を使用すると、コンストラクタ関数の呼び出し側に new
キーワードを使用するように強制できます。それ以外の場合は、次のようにエラーをスローできます。
function Person(firstName, lastName) {
if (!new.target) {
throw Error("Cannot be called without the new keyword");
}
this.firstName = firstName;
this.lastName = lastName;
}
Code language: JavaScript (javascript)
または、コンストラクタ関数のユーザーが new
キーワードを使用しない場合は、新しい Person
オブジェクトを作成することで構文をより柔軟にすることができます。
function Person(firstName, lastName) {
if (!new.target) {
return new Person(firstName, lastName);
}
this.firstName = firstName;
this.lastName = lastName;
}
let person = Person("John", "Doe");
console.log(person.firstName);
Code language: JavaScript (javascript)
このパターンは、構文をより柔軟にするために、JavaScript ライブラリやフレームワークでよく使用されます。
要約
- JavaScript のコンストラクタ関数は、複数の類似したオブジェクトを作成するために使用される通常の関数です。