LoginSignup
17
18

More than 5 years have passed since last update.

JavaScriptのprototype理解メモ

Last updated at Posted at 2014-03-16

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

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

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に文字列を代入すると直接値を書き換えているはずです。

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

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という謎のプロパティが気になるので引き続き調査する。

17
18
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
18