functionによるJavaScriptクラスとprototype

JavaScriptでは、function文で「オブジェクトの設計図」となるクラスを作ることができます。

具体的には、名前を付けた関数を定義しておくと、その関数名で「new」を呼び出した時に新たなオブジェクトが作られ、そのprototypeに関数オブジェクトのprototypeが設定されます。そして、prototypeに設定されている関数オブジェクトは

オブジェクト.関数名()

の形で呼び出せるのです。

つまり、JavaScriptではオブジェクトのprototypeが事実上のクラス(オブジェクトが持つ関数の列挙)になるわけですね。実際、JavaScriptではprototypeが「オブジェクトの性質、実行時の動作」を決める根幹で、JavaScriptはprototypeベースのオブジェクト指向言語とも呼ばれています。

ただし、prototypeはすべてのオブジェクトで「共有」される点に注意してください。prototypeの関数を書き換えると、すべてのオブジェクトが影響を受けます。

まず、以下のコードを見てみましょう。

function a() {

}

a.prototype.b = { alert("b"); };

var a1 = new a();

a1.b()

このコードを実行したときには、a1.b()に設定されているfunctionのコードが実行されます。そして、この例では「alert("b")」ですから、「b」が表示されるわけです。

次に、以下のコードはどうでしょう?

function a() {

}

a.prototype.b = function() { alert("b"); };

var a1 = new a();
var a2 = new a();

a.prototype.b = function() { alert("ba"); };

a1.b();

今度は、a1を生成した「後」に書き換えたa.prototype.b()が実行され「ba」が表示されます。functionのprototypeを書き換えると、「その前に生成したオブジェクトのメンバ関数」も置き換わるわけです。

もっとも、これは「クラスに定義されている関数」を書き換えればどうなるか、という流れで考えると「当たり前」のことではあるのですが・・・ただ、JavaScriptでは「オブジェクト.関数名()」で実際にどの関数が呼び出されるのか一見わかりにくくなることがあるので、意外にはまります。

オブジェクトごとに関数のコードを変えたいときは、オブジェクトの関数を直接書き換えるようにしましょう。

たとえば、先の例なら

a2.b = function() { alert("ba"); };
とするわけです。これで、a2.bは「新たに生成される関数オブジェクト」になる(a.prototype.bと切り離される)ので、a1.b()が変更されることはなくなります。