JavaScriptのプロトタイプがやっとわかってきた(気がする)

JavaScriptのプロトタイプがやっとわかってきた(気がする)。混乱の原因は__proto__とprototypeがごっちゃになってたことだな。

newでオブジェクトを作った場合、

JavaScript における new 演算子の動作は大まかにいって以下のとおりである。(new F() とした場合。)

   1. 新しいオブジェクトを作る。
   2. 1 で作ったオブジェクトの [[Prototype]] 内部プロパティ (__proto__ プロパティ) に F.prototype の値を設定する。
          * F.prototype の値がオブジェクトでないのなら代わりに Object.prototype の値を設定する。
   3. F を呼び出す。このとき this の値は 1 で作ったオブジェクトとし、引数には new 演算子とともに使われた引数をそのまま用いる。
   4. 3 の返り値がオブジェクトならそれを返す。そうでなければ 1 で作ったオブジェクトを返す。

ここで「オブジェクトである」というのはプリミティブ値 (文字列、数値、真偽値、undefined 、null) ではないということだ。new String("string") 、new Number(123) 、new Boolean(true) はオブジェクトだが "string" 、123 、true はオブジェクトではない。

from JavaScript の new 演算子の意味: Days on the Moon

なので以下のソースの場合、u.__proto__にUser.prototypeが設定される。

function User(name) {
  this.name = name;
}
var u = new User("hoge");

実際console.log(u.__proto__ === User.prototype)はtrueになる。

オブジェクトの__proto__にFunctionオブジェクトのprototypeが入る。

絵で描くとこんな感じかな。

継承使った場合のソースと絵は以下のような感じ。オブジェクトの__proto__(Functionオブジェクトのprototype)を辿っていく。Object.prototype.__proto__はnull。
c.eat()のように存在しないプロパティを参照した場合はエラーになる。

var Animal = function(){}
Animal.prototype.walk = function() {
  console.log("walk");
}

var Cat = function(){}
Cat.prototype=new Animal();
Cat.prototype.cry = function() {
  console.log("cry");
}

var c = new Cat();

console.log(c.__proto__ === Cat.prototype);//true
console.log(Cat.prototype.__proto__ === Animal.prototype);//true
console.log(Animal.prototype.__proto__ === Object.prototype);//true
console.log(Object.prototype.__proto__ );//null
c.walk();//walk
c.cry();//cry