prototype図示とnewの挙動

多くの方に読んでもらえたのが何より嬉しい。
ブログ、書いて良かった、純粋に。ありがとうございます。


でも、はてぶページとか社内とかで、
「でも...もう一歩しっくりこない」という声もあって。。


話をしてて、以下の2つが理解できると、
Javascriptのprototype指向がしっくりくる(かもしれない)ことがわかった。
で、僕なりにそれをまとめてみようと思った。(くどくない程度に^^;)


それは次の(1)と(2)の理解である。
(1)prototypeとオブジェクトの関連を図でイメージする。
(2)newの挙動を把握する。


この2つをきっちり理解すれば、
少なくとももう少しprototype指向がしっくりくると思う。


だから、前の記事でよく分からなかった人は、読んでいただければと思う。

題材は前回の記事と同じく、赤い箱と青い箱を取り上げる。

var Box = function(size){
    this.size = size;
}
Box.prototype = { color: "red" };
var redBox1 = new Box(10);
var redBox2 = new Box(11);
Box.prototype = { color: "blue"};
var blueBox = new Box(12);

(1)prototypeとオブジェクトの関連

まずは、(1)prototypeとオブジェクト{}の関連を図でイメージする。

オブジェクトとprototypeの関係が直観的に理解できるかもしれない。


ポイントは、

redBox1, blueBoxは、BoxやBox.prototypeを見ているのではなく、
{ color: ** }のオブジェクトを指している(参照をもっている)

ということだ。
クラス指向の考えを引きずると、redBox1, blueBoxは、
BoxとかBox.prototypeを指しているように誤解しやすい。


Box.prototypeは実行時に決まるオブジェクトを指している。
(ややくどいけど)だから、上のコードの後に以下のようにすると...

Box.prototype = redBox1.prototype;
Box.prototype.color = "yellow";
alert(redBox1.color); //yellow
alert(redBox2.color); //yellow
alert(blueBox.color); //blue

(Box.prototypeが指すオブジェクトを青い箱から赤い箱に変えた。)

これらの結果が前より納得いくものとなっていたら幸いである。

(2)newの挙動

(1)のprototypeが理解できたら、あとはnewが理解できれば、
javascriptのprototypeに大してビビることはなくなると思う。


newに関しては、僕はこの記事がすごく分かり易かった

JavaScript の new 演算子の意味

だから、nanto_viさんの文言をお借りし、書いてみる。


例えば、この新しい青い箱を作るという処理を思い浮べて、読んでもらえればとおもう。

var blueBox = new Box(12);

"new" の挙動

  1. 新しいオブジェクト{}を作成する
  2. 1で作成したオブジェクトのprototypeに、Box(関数オブジェクト)のprototypeが格納している参照を格納する。(上の例では、{color: "blue"}オブジェクトへの参照)
  3. 1で作成したオブジェクトへの参照を、関数Box内のthisにセットし、関数Boxを呼び出す。引数が記述されていれば(例では12), それを関数Box実行の引数とする。
  4. 1で作成したオブジェクトへの参照を返す。


正確な定義はひとまず置いておいて、これがnewの挙動である。
新しく作るオブジェクトの初期化を行いたい場合ば、
Boxの処理の中に this を記述すれば、初期化処理を行うことができる。

var Box = function(size) {
  this.size = size;
};

Box.prototypeが指すオブジェクトに影響を与えず、
新たに作成したオブジェクトにだけ処理[ex.プロパティを追加]をしている。

こうした関数オブジェクトBoxはコンストラクタと呼ばれるが、
new との協業によって新たなオブジェクトを作成していることからも、まさしくコンストラクタである。

一方、クラスというものは存在しない。
実際Ecmascriptの仕様書にも、
コンストラクタは明記されているが、クラスという言葉は出てこない。
(全部隅から隅まで見たわけではありません、、、^^;)


一般に言うクラスの役割をするのは、
まさにBox.prototypeが指しているオブジェクトであり、
これがprototype指向の核なのかな、と思った。


以上、分かっている人には当たり前の、つまらない説明かもしれないが、
少しでも納得した人がいてくれたら、幸せだなぁと思います。

prototypeを把握した上で、
prototype.jsを読んでみるのも面白いと思います。(extendとか)