もやもやエンジニア

IT系のネタで思ったことや技術系のネタを備忘録的に綴っていきます。フロント率高め。

プロトタイプベースのjavascript設計 (2)

前回はこちら

プロトタイプベースのjavascript設計 (1)
http://rei19.hatenablog.com/entry/2013/05/21/005713

コンストラクタを作ってnewを使うとprototypeを引き継いだオブジェクトを作るよ!というところまで書きました。

今回はjavascriptにおける継承の概念について書いてみます。

とりあえずポピュラーな形はこんな感じ。

var App = App || {};
App.Base = (function(){
	// コンストラクタ
	function Base(){}

	// 初期化処理
	Base.prototype.Initialize = function(){
		// 引数をプロパティにせっと
		this.name = arguments[0];
		this.id = arguments[1];
	}
	// 確認用
	Base.prototype.showProperty =function(){
		console.log(this.name);
		console.log(this.id);
	}
	return Base
})();
App.Hoge = (function(){
	// コンストラクタ
	function Hoge(){
		this.Initialize.apply(this, arguments);
	}

	// プロトタイプ継承
	Hoge.prototype = new App.Base;

	// メソッド定義
	Hoge.prototype.tekitou = function(){
		// ロジック
		return 'Hogeだお';
	}

	return Hoge;
})();

本筋の話ではないですが、javascriptの開発をしていると必ず出てくる問題はグローバル空間の汚染で、ある程度の規模の開発であれば気を使うべきでしょう。
そんな訳で、サンプルコードではAppにコンストラクタを追加していくという構造にしています。

んでは、継承の話に戻って上からコードを解説します。

まずはBaseというコンストラクタを作って、InitializeとshowPropertyというメソッドを追加しています。
これが継承元のプロトタイプとなります。

ちなみにコンストラクタを作る際、無名関数の即時実行とクロージャを使ってグローバル空間の汚染を防いでいます。
使わないで書くとこんな感じ。

var App = App || {};
// 書き方①
function Base(){
        this.Initialize = function(){
		// 引数をプロパティにせっと
		this.name = arguments[0];
		this.id = arguments[1];
	}
        this.showProperty = function(){
		console.log(this.name);
		console.log(this.id);
	}
}
App.Base = Base;

// 書き方②
function Base(){}
Base.prototype.Initialize = function(){
	// 引数をプロパティにせっと
	this.name = arguments[0];
	this.id = arguments[1];
}
Base.prototype.showProperty =function(){
	console.log(this.name);
	console.log(this.id);
}
App.Base = Base;

どちらもBaseという名前がグロ−バル空間に残ってしまうという問題があります。
①と②の違いはprototypeを使っているか使っていないかの違いですね。
①はnew でオブジェクトが作られる度にInitializeとshowPropertyの関数が生成されるのでメモリ的によろしくありません。
②の書き方であればBaseのprototypeを見るのでnewしたときによけいなメモリを使いません。
※なんのこっちゃと思う人はプロトタイプチェーンでぐぐるといいっす。

で、その次にHogeというコンストラクタを作っています。
注目するのはまず、Hogeのコンストラクタの定義後のコード

	function Hoge(){
		this.Initialize.apply(this, arguments);
	}
	// プロトタイプ継承
	Hoge.prototype = new App.Base;

	// メソッド定義
	Hoge.prototype.tekitou = function(){
		// ロジック
		return 'Hogeだお';
	}

HogeのプロトタイプにBaseのオブジェクトをセットしています。
継承先のプロトタイプに継承させたいオブジェクトをセットする。これがjavascriptの継承です。

コンストラクタの中身を見るとこんな感じ

f:id:Rei19:20130525191642p:plain

Hogeのprototypeは何もしなければHogeになりますがBaseを継承しているのでBaseになっています

次にHogeのコンストラクタ内を見てください。Baseで定義したInitializeをコールしています。
newを使ってHogeのオブジェクトを作るとBaseで定義したInitializeが呼ばれてプロパティに値がセットされるという流れになります。
もちろん作ったHogeオブジェクトからはBaseのshowPropertyメソッドも問題なく呼べます。

以上がスタンダードなjavascriptの継承の話でした。

webサービスでリッチコンテンツが増え、クライアント側でのMVCアーキテクチャの整理なんかをするタイミングが来たら、この辺の話は抑えておくと綺麗な設計が出来るかなと思いますた。