JavaScript コンストラクタ関数

概要: このチュートリアルでは、JavaScript コンストラクタ関数と、その new キーワードを使用してオブジェクトを作成する方法について学習します。

JavaScriptコンストラクタ関数の概要

JavaScript オブジェクトのチュートリアルでは、オブジェクトのリテラル構文を使用して新しいオブジェクトを作成する方法を学習しました。

たとえば、次の例では firstNamelastName という 2 つのプロパティを持つ新しい person オブジェクトを作成します。

let person = {
    firstName: 'John',
    lastName: 'Doe'
};Code language: JavaScript (javascript)

実際には、person オブジェクトなどの類似したオブジェクトを数多く作成する必要があります。

これを行うには、カスタムタイプを定義するコンストラクタ関数と、このタイプから複数のオブジェクトを作成する new 演算子を使用します。

技術的には、コンストラクタ関数は次の規約を持つ通常の 関数 です。

  • コンストラクタ関数の名前は、PersonDocument など、大文字で始まります。
  • コンストラクタ関数は、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' をオブジェクトの firstNamelastName プロパティに割り当てます。
  • 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 関数の内部の thisperson 変数ではなく グローバルオブジェクト に結び付けられます。

firstName または lastName プロパティにアクセスしようとすると、エラーが発生します。

console.log(person.firstName);Code language: CSS (css)

エラー

TypeError: Cannot read property 'firstName' of undefinedCode language: JavaScript (javascript)

同様に、getFullName() メソッドはグローバルオブジェクトに結び付けられているため、アクセスできません。

person.getFullName();Code language: CSS (css)

エラー

TypeError: Cannot read property 'getFullName' of undefinedCode 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)

出力

undefinedCode 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 のコンストラクタ関数は、複数の類似したオブジェクトを作成するために使用される通常の関数です。
このチュートリアルは参考になりましたか?