[メモ][JavaScript] コンストラクタとプロトタイプ

JavaScriptで、初期化と同時にオブジェクトにメソッドを持たせるには、(継承を除くと)2つの方法があります。コンストラクタでメソッド定義する方法と、プロトタイプオブジェクトのメソッドとして定義する方法です。

// コンストラクタ
var Member = function(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
this.getName = function(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
}
// プロトタイプ
var Member = function(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
Member.prototype = {
getName: function() {
return this.lastName + ' ' + this.firstName;
}
}

いずれの方法でも、MemberオブジェクトにgetName()メソッドが定義されます。違いは、メモリの使い方にあります。

コンストラクタは、インスタンスを生成する度に、それぞれのインスタンスのためにメモリを確保します。同じ処理を行うメソッドでも、インスタンスが異なればそれぞれのメソッドのぶん、メモリを消費します。

一方、プロトタイプオブジェクトは、元となるオブジェクトから暗黙的に参照されています。あるオブジェクトを元に複数のインスタンスを作ったとしても、メソッドはプロトタイプオブジェクトに定義されている1つだけです。

そのため、メソッド定義はコンストラクタで行うよりも、プロトタイプオブジェクトに持たせたほうが、メモリ効率が良くなります。

また、プロトタイプオブジェクトを変更すれば、同一のオブジェクトからインスタンス化された全てのオブジェクトに変更が行き渡る、という点も、プロトタイプの特徴です。

なお、「初期化と同時」という条件を外せば、以下のような追加も可能です。

var mem = new Member('John', 'Smith');
mem.getName = function () {
return this.lastName + ' ' + this.firstName;
}

この場合、Memberオブジェクトをインスタンス化したmemオブジェクトにはgetName()メソッドが追加されますが、この追加が別のMemberオブジェクトに影響を及ぼすことはありません。

また、メソッドやプロパティが呼び出された際の探索の順番は、(1) オブジェクト自身のメソッド・プロパティ (2) オブジェクトが参照しているプロトタイプオブジェクトのメソッド・プロパティ となります。そのため、↓のように、オブジェクト自身とプロトタイプに、同じ名前で別の処理を行うメソッドを追加した場合、オブジェクト自身に持たせたメソッドの方が優先されます。

var mem = new Member('John', 'Smith');
mem.getName = function () {
return this.lastName + ' ' + this.firstName; // last + first
}
Member.prototype = {
getName: function () {
return this.firstName + ' ' + this.lastName; // first + last
}
}
console.log(mem.getName()); // Smith John


コメントを残す

コメントを残す