【JavaScript】 プロトタイプ/プロトタイプチェーン
環境 CentOS 7.0 JavaScript Node.js 0.12.2
プロトタイプと通常のプロパティの違い
// prototypeを設定 var Hoge = function() {} Hoge.prototype.a = 1; // プロパティを設定 var Fuga = function() { this.a = 1; } var hoge0 = new Hoge(); var fuga0 = new Fuga(); console.log(hoge0.a); // 1 console.log(fuga0.a); // 1
これだけ見ると、結果は全く同じになる。
では何が違うのか?
以下のようにしてみる。
var fuga1 = new Fuga(); var fuga2 = new Fuga(); // fuga1.aプロパティに2を設定 fuga1.a = 2; // 各プロパティはインスタンス毎に、別に保持されているので、当然値は異なる console.log(fuga1.a); // 2 console.log(fuga2.a); // 1
var hoge1 = new Hoge(); var hoge2 = new Hoge(); // これはprototypeを参照している console.log(hoge1.a); // 1 // プロパティにa = 2を設定 hoge1.a = 2; // prototypeではなく、プロパティaを参照 // このときprototypeは見えなくなる console.log(hoge1.a); // 2 // プロパティaを削除 delete hoge1.a; // 再びprototypeが見える。hoge2も同じくprototypeが見える console.log(hoge1.a); // 1 console.log(hoge2.a); // 1 // ここで、prototypeの値を変更する Hoge.prototype.a = 3; // prototypeを参照する、2つの値が両方とも変更されている console.log(hoge1.a); // 3 console.log(hoge2.a); // 3
これからわかるのは次の2点
- prototypeと同じ名前のプロパティが設定されると、prototypeはプロパティに隠され見えなくなる。
ただし、その場合もprototypeは削除されたわけではい。 - インタンスはprototypeの参照を持っている。
そのため、prototypeが変更されると、そのインスタンスのプロパティやメソッドは全て変更される。
プロトタイプチェーン
var Animal = function(){}; Animal.prototype = { category : function(){return '哺乳類';} } var Dog = function(){}; Dog.prototype = new Animal(); Dog.prototype.type = function(){return '犬';} var d = new Dog(); console.log(d.type()); // 犬 console.log(d.category()); // 哺乳類
つまり、もしインスタンスメソッドにも、そのクラスのprototypeメソッドにも、指定のメソッド(ここではcategory())が無いとき、自動的にprototypeをさかのぼりスーパークラスのprototypeを探す。
これをプロトタイプチェーンと呼ぶ。
クラスがパッと見、functionとなっていて、JavaやPHPなどと異なって見えるが、用はサブクラスのインスタンスが、サブクラスにメソッドが定義されていないときに、スーパークラスを探しに行く、という一般的な仕組み。
一般的な言語と大きく異なるのは、インスタンスを生成後に、継承されたメソッドやプロパティを変更する事ができる事だ。上記の例で、
console.log(d.type()); // 犬 console.log(d.category()); // 哺乳類 // Animalのprototpyeを変更 Animal.prototype.category = function(){return 'Mammal';} console.log(d.category()); // Mammal
このように継承元のprototypeを変更すれば、参照しているだけのサブクラスのインスタンスのprototpyeメソッドやプロパティも変更される。