7.2 プロトタイプとプロトタイプチェーン

コンストラクタ関数とは、関数を使って複数のオブジェクトを簡単に生成する仕組みです。これは Java のコンストラクタと同様に、new キーワードを使ってインスタンス(実体)を生成するための雛形(ひながた)となります。

7.1.1 コンストラクタ関数を用いたプログラム

コンストラクタ関数を用いて JavaScript を記述するやり方を学んでみましょう。

ソースフォルダ:public/ch07

ファイル名:constructor.js

➢ constructor.html

前の章で作った ch06/ json.html をコピーし、ch07 にペーストしてください。
その際に、ファイル名を constructor.html に変更します。
ファイル内の json.html や json.js の記述も、constructor.html や constructor.js に修正します。

➢ constructor.js

// constructor.js

// ユーザーオブジェクトを作るための「コンストラクタ関数」を定義します
function User(name, age) {
    this.name = name;
    this.age = age;
    this.greet = function() {
        return `こんにちは、私の名前は ${this.name} です!`;
    };
}

// newキーワードを使って、実際のデータ(インスタンス)を作成します
const user1 = new User("Alice", 25);
const user2 = new User("Bob", 30);

// 結果を表示します
alert("ユーザー1: " + user1.greet());
alert("ユーザー2: " + user2.greet());

実行結果

解説

このプログラムでは、名前と年齢を持つ「ユーザー」という共通の形を定義し、そこから 2 人のユーザーを作成しています。4 行目で User という名前のコンストラクタ関数でユーザーオブジェクトを定義しています。コンストラクタ関数では、関数名の頭文字を大文字にするのが慣例です。

4: function User(name, age) {

13 行目で new キーワードを使って user1 という名前でコンストラクタ関数のインスタンス(実体)を生成します。引数で与えられた値は、コンストラクタ関数内の記述に従い、内部にプロパティとして保持されます。このようにコンストラクタ関数内で定義されたプロパティやメソッドは、new キーワードで新たにインスタンスが作られるたびに、新しくコピーされます。

13: const user1 = new User("Alice", 25);

ただ、このコンストラクタ関数は、使い方によってはメモリを無駄に使ってしまうという問題点があります。プロパティ(データ)はインスタンスごとに異なる値を持つため、個別に持つ必要があります。しかし、メソッド(処理)は、すべてのインスタンスで共通の内容であることがほとんどです。

それにもかかわらず、コンストラクタ関数内でメソッドを定義してしまうと、new するたびに同じ処理内容のメソッドが個別に作られ、それぞれのインスタンスを持つことになります。これだとインスタンスの数が増えれば増えるほど不要なメモリを消費してしまうことにつながります。

上記のソースコードは 7 行目の this.greet の部分がそれに該当します。

7: this.greet = function() {

このプログラムでは、扱う人数が少ないうちはいいですが、データが増えて new キーワードを使うたびにthis.greet の分だけメモリを消費していくことになります。コンストラクタ関数は、複数のオブジェクトを簡単に生成できる反面、より大規模な開発で、一度に大量のオブジェクトを保持する時に問題となる可能性があります。

この問題を解消する方法が、1章でも説明したプロトタイプです。