読者です 読者をやめる 読者になる 読者になる

プロトタイプ

JavaScriptの肝になるプロトタイプのことを実はよく理解してなかったorz
サイ本を読んで整理してみる。

  • すべてのオブジェクトはprototypeオブジェクトを持ち、その全プロパティを継承する
  • コンストラクタでオブジェクトが生成される時、オブジェクトのprototypeには関数のprototypeが指定される
  • prototypeオブジェクトはコピーされるわけではなく、参照される

実際に試してみる

var Person = function (name) {
    this.name = name;
};
Person.prototype.say = function() {
    alert('My name is ' + this.name);
};


taro.prototypeというプロパティがあるわけではないが、sayメソッドが使えるということは内部的に設定されてるということか。

var taro = new Person('Taro');
taro.say();

console.log(typeof(taro.prototype));   // undefined
console.log(typeof(Person.prototype)); // object

もちろんStringでも同じ。

var str = new String('foo');
console.log(typeof(str.prototype)); //undefined


つまり、prototypeは関数オブジェクト(コンストラクタ)に設定してこそ意味があるということ。知ってる人には何をアホなことをという感じだろうが、これが分かってなかった。もう少し試してみる。

var obj  = {num:1};
var func = function(){};

if(func.prototype != undefined) {alert('func has prototype');}
if(obj.prototype  == undefined) {alert('object does not have prototype');}

関数オブジェクトにはprototypeプロパティが定義されてるが、普通のオブジェクトには定義されていない。だんだん分かってきたぞ、と。

継承

OOPにおける重要なコンセプトである継承をJavaScriptで書いてみる。ちなみにJavaScriptはプロトタイプベースなので、クラスという概念はないけど便宜的にコンストラクタ関数をクラスとみなせるので、以下そう書いておく。

  • Humanクラス
var Human = function() {
    this.initialize.apply(this, arguments);
};
Human.prototype.initialize = function(prop) {
    this.name = prop.name || '';
    this.hair = prop.hair || '';
};
Human.prototype.say = function() {
    alert('My name is ' + this.name + '.');
    alert('My hair is ' + this.hair + '.');
};
  • Japaneseクラス
var Japanese = function() {
  // Humanクラスのinitializeを呼び出す
    this.initialize.apply(this, arguments);
    // 追加でプロパティセット
    this.hair = 'black';
};
// prototypeによる継承
Japanese.prototype = Human.prototype;

// 拡張メソッド
Japanese.prototype.eat = function() {
    alert('use chopstick');
};
  • 使ってみる
var taro = new Japanese({name:'Taro'});
taro.say(); // My name is Taro. My hair is Black
taro.eat(); // use chopstick

var tom = new Human({name: 'Tom', hair:'Brown'});
tom.say(); // My name is Tom. My hair is Brown

まとめ

  • prototypeプロパティは普通のオブジェクトからは参照できないが、関数オブジェクトでは参照ができる
  • JavaScriptの継承はprototypeを使って実現される
  • Child.prototype = Parent.prototypeとすればよい