プロトタイププロパティの勉強をしていて、クロージャを使った関数を、プロトタイプオブジェクトのプロパティに設定したときと、インスタンスのプロパティにメソッドとして設定したときの関数の挙動の違いを発見したので、そのメモです。

まず、こんなクラスを定義してみます。※このコードを実行するときは色のついた部分を片方コメントアウトしてから実行して下さい。

function Student(j, m, e) {
this.japanease = j;
this.math = m;
this.english = e;

this.exam = (function() {
var effort = 0;

return function(){
return this.japanease + this.math + this.english + effort++;
};
})();

}
Student.prototype.exam = (function() {
var effort = 0;

return function(){
return this.japanease + this.math + this.english + effort++;
};
})();


var bunkei = new Student(80, 50, 65);
var rikei = new Student(50, 80, 65);

document.write("文系<br />");
document.write("==>", bunkei.exam(), "<br />");
document.write("==>", bunkei.exam(), "<br />");
document.write("==>", bunkei.exam(), "<br />");
document.write("理系<br />");
document.write("==>", rikei.exam(), "<br />");
document.write("==>", rikei.exam(), "<br />");
document.write("==>", rikei.exam(), "<br />");

あるクラスのプロトタイプオブジェクトにメソッドを設定した場合

あるクラスのインスタンスとメソッドの関係は以下のようになります。これはソースコードのピンク色の部分を使用した場合です。

インスタンスとメソッドの関係(プロトタイプオブジェクト)

Student クラスの全てのインスタンスは全く同じ関数 exam を使用します。そのとき各インスタンスは関数 exam 中の同じ変数 effort を使用します。
<=== 実行結果 ===>
文系
==>195
==>196
==>197
理系
==>198
==>199
==>200

あるクラスのインスタンスにメソッドを設定した場合

あるクラスのインスタンスとそのインスタンスメソッドの関係は以下のようになります。これはソースコードのオレンジ色の部分を使用した場合です。

インスタンスとメソッドの関係(インスタンスメソッド)

Student クラスの各インスタンスはそれぞれ exam という関数を自分専用に一つずつ持っています。このとき各インスタンスはそれぞれが保有している関数 exam 中の変数 effort を使用します。 bunkei と rikei が持っている関数は別のものです。名前が違う内容が同じ関数を bunkei と rikei が保有しているイメージ。実際には関数名は同じ exam だがスコープが違う。(これをクロージャという、…はず。)
<=== 実行結果 ===>
文系
==>195
==>196
==>197
理系
==>195
==>196
==>197

最後に

実際には、クラスのインスタンスにメソッドを持たせる場合、プロトタイプオブジェクトにメソッドを設定する方が一般的。(ピンク色の方)そうしつつオレンジ色の時のような実行結果を期待するときには、クラスのオブジェクトにプロパティを一つ追加すれば解決する。今回はあくまで二つの方法による違いを検証しただけです。