JavaScriptのprototype理解メモ

仕事でJavaScriptだけで通信したりアニメーションしたりする機能を実装しなくちゃいけなくなったので、JavaScriptを始めから勉強中です。

この方のスライドを見てprototypeがイメージできなかったので、自分なりに整理するプログラムを書きました。
http://www.slideshare.net/yuka2py/javascript-23768378

```js:script.js
var Person = function(name) {
	this.name = name;
}

console.log(Person);
//console.log(Persion.name)				// Persionはただのfunctionなので当然nameはもっていない

Person.prototype.name = 'A';
console.log('Person.prototype.name : ' + Person.prototype.name);		// 「A」

Person.prototype.say = function() {
	console.log('My name is ' + this.name);
}
Person.prototype.say();					// say関数実行時のthisはPersonなので、「A」	

var p = new Person('B');				// Personオブジェクト生成	
// この時点のpのプロトタイプチェインはこのようになった
// Person
// ├──name: "B"
// └──__proto__: Object
// 　　├──constructor: function (name) {
// 　　├──name: "A"
// 　　├──say: function () {
// 　　├──__proto__: Object

console.log('p.name : ' + p.name);		// 「B」
p.say();								// 「B」		thisはp


// new実行時に__proto__はPerson.prototypeを指す為、true
console.log(Person.prototype.name === p.__proto__.name);

var p2 = new Person('C');
// この時点のp2のプロトタイプチェイン
// Person
// ├──name: "C"
// └──__proto__: Object
// 　　├──name: "A"
// 　　├──constructor: function (name) {
// 　　├──say: function () {
// 　　├──__proto__: Object

console.log('p2.name : ' + p2.name);	// 「C」
p2.say();								// 「C」		thisはp2

Person.prototype.name = 'あ';
console.log('Person.prototype.name:' + Person.prototype.name);		// 「あ」

var p3 = new Person('い');
// この時点のp3のプロトタイプチェイン
// Person
// ├──name: "い"
// └──__proto__: Object
// 　　├──name: "あ"
// 　　├──constructor: function (name) {
// 　　├──say: function () {
// 　　├──__proto__: Object

console.log('p3.name : ' + p3.name);	// 「い」
p3.say();								// 「い」	thisはp3
console.log('p3.__proto__.name:' + p3.__proto__.name);		// 「あ」

Person.prototype.name = 'う';
console.log('Person.prototype.name:' + Person.prototype.name);		// 「う」

console.log('p3.name:' + p3.name);		// 「い」
p3.say();								// 「い」	thisはp3
console.log('p3.__proto__.name:' + p3.__proto__.name);		// 「う」
// この時点のp3のプロトタイプチェイン
// Person
// ├──name: "い"
// └──__proto__: Object
// 　　├──name: "う"         // 上で参照先のprototype.nameを変更したので反映されている
// 　　├──say: function () {
// 　　├──constructor: function (name) {
// 　　├──__proto__: Object

var p4 = new Person('え');
console.log('p4.name:' + p4.name);		// 「え」
p4.say();								// 「え」	thisはp4
console.log('p4.__proto__.name:' + p4.__proto__.name);		// 「う」

// この時点のp4のプロトタイプチェイン
// Person
// ├──name: "え"
// └──__proto__: Object
// 　　├──name: "う"
// 　　├──say: function () {
// 　　├──constructor: function (name) {
// 　　├──__proto__: Object

```

それぞれのプロトタイプチェインを見ると
スライドのポイントにあった「newObj.__proto__ = Person.prototype」に
なっていますね。

ただし、上記のプログラムはnameに代入している文字列は基本型と呼ばれる型なので、
Person.prototype.nameに文字列を代入すると直接値を書き換えているはずです。

なにが言いたいかというと参照型（オブジェクト）を入れると動作が変わります。

```js:script.js
Person.prototype = { name : 'Zeus' }	// オブジェクト
console.log('Person.prototype.name : ' + Person.prototype.name);		// 「Zeus」

var p5 = new Person('か');
console.log('p5.name : ' + p5.name);		// 「か」
console.log('p5.__proto__.name:' + p5.__proto__.name);		// 「Zeus」
// この時点のp5のプロトタイプチェイン
// Person
// ├──name: "か"
// ├──__proto__: Object
//　　　├──name: "Zeus"
//　　　├──__proto__: Object

Person.prototype = { name : 'Hades' }	// 参照先を変更する
console.log('Person.prototype.name : ' + Person.prototype.name);		// 「Hades」

var p6 = new Person('き');
console.log('p6.name : ' + p6.name);		// 「き」
console.log('p6.__proto__.name:' + p6.__proto__.name);		// 「Hades」
// この時点のp6のプロトタイプチェイン
// Person
// ├──name: "き"
// ├──__proto__: Object
// 　　├──name: "Hades"
// 　　├──__proto__: Object

console.log('p5.name : ' + p5.name);		// 「か」
console.log('p5.__proto__.name:' + p5.__proto__.name);		// 「Zeus」
// この時点のp5のプロトタイプチェイン
// Person
// ├──name: "か"
// ├──__proto__: Object
//　　　├──name: "Zeus"   // Zeusのまま
//　　　├──__proto__: Object
```

なぜZeusのままかについては、↓のURLがわかりやすかった。
http://tacamy.hatenablog.com/entry/2012/12/17/000931

ここまで整理したが、constructorという謎のプロパティが気になるので引き続き調査する。