JavaScriptのオブジェクト指向2

JavaScriptのクラスについて、その2。
まだ理解までは遠い。。

JavaScriptのクラス
空のクラスを作る。
var Class = function() {};	//(1-1)
function Class() {};		//(1-2)

二通りの書き方だけれどやってることは同じ。で、これって関数じゃん?

空じゃないクラスを作ってみる。

2次元の点を表すPointクラス

var Point = function(_x,_y){
	this.x = _x,
	this.y = _y,
	this.DisplayPoint = function(){
		alert(this.x+','+this.y);
	}
};	//(2-1)

function Point( _x, _y ) {
	this.x = _x;
	this.y = _y;
	this.DisplayPoint = function(){
		alert(this.x + ',' + this.y);
	};
	return this;
};	//(2-2)

こちらも書き方二通り((2-1),(2-2))。もっといろんな書き方ありそう。
ここまできて、あぁこれってクラスのコンストラクタか!と気づいた。確かに関数。コンストラクタで初期化することが、クラスからオブジェクトを作るっていうこと。
newして新しいオブジェクトを作るということに納得。引数も与えられます。(3-1)

var position1 = new Point( 10, 20 );	//(3-1)
var position2 = new Point( 150, 230 );	//たくさん作れる!
position1.DisplayPoint();		//'10,20'を表示 (3-2)
position1.DisplayPoint();		//'150,230'を表示 (3-3)

このときのthisはPointでなく、それぞれposition1、position2に渡され、そのオブジェクトを指す。
クラスを使えば同じプロパティを持つオブジェクトをたくさん簡単に作れる。

プロトタイプ prototype

JavaScript特有の難しいところ^^
ここでは箇条書きのメモ程度に。。

  • オブジェクトは全てprototypeプロパティというものを持っている
  • 特に指定せずにオブジェクトを作ったときにはprototypeにはデフォルト指定される。
  • オブジェクトのあるプロパティにアクセスしようとして、プロパティが無ければprototypeに無いかどうかを暗黙に参照する
  • prototypeにプロパティを自由に追加 / 代入できる

prototypeはオブジェクトの雛形。という説明をちらほら見るけれど、よくわからないです。。

プロトタイプによる初期化

コンストラクタでない、オブジェクト初期化方法。
とりあえずやってみる。

var Point = function( _x, _y) {
	this.x = _x;
	this.y = _y;
};	//(4-1)
var position1 = new Point( 10, 20 );	//(4-2)

Point.prototype = {
	DisplayPoint : function() {
		alert(this.x + ',' + this.y);
	}
};	//プロトタイプによる初期化 (4-3)

var position2 = new Point( 10, 20 );	//(4-4)

position1.DisplayPoint();		//未定義!(4-5)
position2.DisplayPoint();		//'10,20'を表示(4-6)

もうすでに定義してあるクラスのコンストラクタに新しく定義を追加するイメージ。なのかな?

クラスに定義するのと、オブジェクトのプロトタイプに定義するのとは微妙に(だいぶ?)違う。指定する名前がクラス内に無ければ、prototypeを暗黙に参照する。
なので、プロパティにアクセスするとき、クラス内にもprototypeにも同じ名前のプロパティがある場合はクラス優先。という風にアクセスする順番がある。このことは後のプロトタイプチェーンのときに重要。

newでオブジェクトが作られるときに、そのクラスのプロトタイプを参照して、そこからプロパティやメソッドを継承する。
逆に言えば、クラスからオブジェクトがnewして作られる前にプロトタイプに格納しないとそのオブジェクトでは定義されていないので注意。(4-5)

プロトタイプチェーン

オブジェクトのプロトタイプには、オブジェクトを代入することができる。
というか、prototypeプロパティもオブジェクトなのでprototypeも内部にprototypeを持っている。というわけのわからないことに。。

このことを利用して、プロトタイプチェーンという不思議なことができるらしい。

var Class1 = function(){
	this.Func1 = function(){
		alert('Func1');
	};
};				//(5-1)

var Class2 = function(){
	this.Func2 = function(){
		alert('Func2');
	};
};				//(5-2)

Class2.prototype = new Class1();	//(5-3)
var test = new Class2();		//(5-4)

test.Func1();	//'Func1'を表示(5-5)

(5-4)でtestはClass2のオブジェクトなのに、(5-5)で、Func1()が正しく実行できます。
"プロパティが無ければprototypeを暗黙に参照する。"ので、

Class2 → Class2.prototype(= Class1 )

というふうに「チェーン」したようなつながりの関係ができる。
このプロトタイプチェーンは、「クラスの継承」みたいなものだな。

目的のプロパティがClass1にも無い場合はさらに、Class1→Class1.prototypeと探していく。ここでClass1.prototypeには特に指定していないので、Objectというものが(暗黙的に)指定される。全てのオブジェクトは最終的に、Object(クラス)に行き着き、Object.prototypeはnullで終わりになっている。
Objectまで探して見つからなければそのプロパティは未定義ということになる。

全部書くと、
Class2 → Class2.prototype (= Class1 ) → Class1.prototype (= Object ) → Object.prototype (= null )
という感じの継承になってる。

prototypeはもっと勉強しよう

この1回で終わらせるつもりが、なんかまだ良くわかってないのでprototypeについてまた別途勉強していこう。
次回以降予定予定
さらにprototype
newについて
イベント処理しよう
prototype.jsを使おう

その他

FireBugを導入した。すごく便利。

参考

関連記事