ああ、JavaScript の prototype ってこういうことだったのかあ。

※ あとで見直したら、一部間違いがあったので後で修正記事を書きます。

はずかしながら prototype についてやっと腑に落ちたよ。

要点はふたつ。

  • JavaScriptの継承とは、オブジェクトの機能を引き継いだ新しいオブジェクトをつくることである。
  • その方法(のひとつ)は、関数の prototype プロパティとnewによる関数の呼び出しで実現されている。


自分が理解したときの思考の流れは以下である。

まず、関数Fを以下のように定義する。

var F = function(){};

この関数をnewで呼び出す。するとオブジェクトが戻る。

var o1 = new F();

このオブジェクトは空のobjectオブジェクトとほとんど同じだ。
違うのは constructor プロパティが関数 F を参照していることくらい。このconstructor プロパティはあまり役に立たないので、とりあえず忘れる。

o1.constructor === F; // true

さて、このままだとちっとも嬉しくないのだけど、ここで prototype プロパティの役割がでてくる。
関数 F の prototype プロパティには、関数を new で呼び出したときに戻るオブジェクトに機能を引き継がせたいオブジェクトを指定するのである。

F.prototype = {
	value:10,
	get:function(){return this.value;},
	set:function(obj){this.value = obj;},
};

で、もう一度newで関数を呼び出す。このとき戻るオブジェクトは prototype に指定したオブジェクトの機能を引き継いでいることが確認できる。

var o2 = new F();
o2.get(); // 10
o2.set(20);
o2.get(); // 20

ちなみに

var F = function() {};
F.prototype = {
	value:10,
	get:function() {return this.value;},
	set:function(obj) {this.value = obj;},
}

と書いたときと

var F = function() {
	this.value = 10;
	this.get = function() {return this.value};
	this.set = function(obj) {this.value = obj};
};

と書いたときの意味は同じである。でも、後者の書き方はあまり役に立たない(と思う)ので忘れる。

だからどうしたって?
ここまでの事実で理解したのは、これこそプロトタイプ継承と呼ばれる JavaScript における継承の仕組みである、ということだ。
まとめると以下のようになる。

  • JavaScript の継承とは、オブジェクトの機能を引き継いだ新しいオブジェクトをつくることである。
  • その方法(のひとつ)は、関数の prototype プロパティとnewによる関数の呼び出しで実現されている。

なんだ、そういうことか。

ただし、プロトタイプ継承のときに prototype の定義と new による関数呼び出しを毎回書くのは面倒なので、以下のように関数化することが多い。

var object = function(obj) {
	var F = function() {};
	F.prototype = obj;
	return new F();
};

こんな感じで使う。

var O = {
	value:10,
	get:function() {return this.value;},
	set:function(obj) {this.value = obj;},
}
var o3 = object(O);
var o4 = object(O);
o3.get(); // 10
o3.set(20);
o3.get(); // 20
o4.get(); // 10
参考