JavaScriptでのクラスの書き方

# JavaScriptでもクラスな考え方をしたい
「JavaScriptにおいて、どうクラスを書くか？」の問いに
「コレだ！」ってのがなかなか見つからなかったが、やっと自分の中で
「**こう書くとシックリくる**」ってのが見つかったのでメモ、って話。


JavaScript言語では「クラス」という概念は無い（※１）。
無いが、「Google流 JavaScript におけるクラス定義の実現方法（※２）」
とかでも「クラス」って表現は普通に使われている。
さて、疑似的に「クラス」を実装するにはどう書けばよいか？

# クラスの記述方針
以下のような方針でクラスを書くと、しっくり来た。

 1. グローバル空間で「var クラス名 = function(){}」にて『**クラスを定義**』する。
 2. **静的メンバ変数のprivateスコープ化**は、クロージャーを使って実現する。
 3. 動的メンバのprivateスコープ化は、『諦める』。

この方針であれば、ある程度のprivate化を行いながらも、
**メソッドはprototypeで定義できる**ので、「メモリへの負荷が無い」
っていうプロトタイプベースの恩恵も享受できる（※３）。


# サンプルコード
具体例としては、以下のようなコードになる。
なお、jqueryとjquery.cookie.js（※４）を利用している。

```js:class_cookie.html
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script type='text/javascript' src='./jquery-1.12.3.js'></script>
<script type='text/javascript' src='./jquery.cookie.js'></script>
<script>

var CookieBind = function( cookieName ){
	// コンスタラクタ
	// ⇒グローバル変数で定義する。
	//
	this._cookieName = cookieName;

	// このタイミングでは未定義のメソッド、も指定可能。
	// ⇒「this」は実行時解決されるから。
	this.itsLoadedStr = this.load(); 
};
(function(){
	//
	// 続いて、prototypeを用いてメソッドを定義
	// ⇒即時関数の中で行うことで、静的praivate変数／メソッドを実装可能。
	// 　クロージャーの仕組みを利用している。
	//
	// ⇒動的なpraivate変数は諦める。
	// 　（メソッドは、適宜thisを渡すことで動的な実装は可能）。
	//
	// ⇒JavaScriptの場合は、メソッドは「静的な枠」＋「動的なメンバ変数」で実装する。
	//
	// ※prototype内で function(){} 定義するときは、thisに注意。
	// 　⇒ function(){ の内部 } では、thisは呼び出し元になり、このクラスインスタンスを指さない。
	// 　⇒ function() の親側で var self = this; して、function(){ の内部 } では、
	// 　　 self.～の形式で呼ぶこと（selfはクロージャーになる）。
	//
	var COOKIE_OPTION = { expires: 7 }; // 静的プライベート変数

	CookieBind.prototype.save = function( str ){
		$.cookie( this._cookieName, str, COOKIE_OPTION );
	};
	CookieBind.prototype.load = function(){
		return $.cookie( this._cookieName );
	};
	CookieBind.prototype.getValue = function(){
		return this.itsLoadedStr;
	}
	CookieBind.prototype.getCookieName = function(){
		return this._cookieName;
	}
	// prototype = {}; は禁止。いろいろ破壊するので、扱いが面倒。
}());




// クラス継承はこちら。
var CookieBind2Input = function( cookieName, id_input, id_button ){
	var self = this;

	CookieBind.call( this, cookieName ); // 継承元のコンスタラクタを明示的に呼び出す。
	this._idInput = id_input;
	this._idButton = id_button;

	this.load2Input();
	$("#" + this._idButton).click( function(){
		self.saveByButton(); // この位置は、thisが異なるので注意。
	});
};
// 親のメソッドを「継承」する。
CookieBind2Input.prototype = Object.create( CookieBind.prototype ); 
// サブクラスでのメソッド追加も、同様に即時関数内で行う。
(function(){
	// 明示的にインスタンスを渡すことで、privateな動的メソッドを実装可能。
	var privateFunc = function( instance, value ){ 
		var str = value + "\r\nをcookie名 ";
		str += instance._cookieName; // 親クラスの動的メンバにアクセス。
		str += " に保存しました！";
		alert( str );
	};

	CookieBind2Input.prototype.load2Input = function(){
		var value = this.getValue();
		if( value ){
			$("#" + this._idInput).val( value );
		}
	};
	CookieBind2Input.prototype.saveByButton = function(){
		var value = $("#" + this._idInput).val();
		if( value.length > 0 ){
			this.save( value );
			privateFunc( this, value );
		}
	};
	CookieBind2Input.prototype.del = function(){
		this.save( null );
	}
}());


// 実行例
$(document).ready(function(){
	var text_cookie1 = new CookieBind( "key-sample1" );
	var text_cookie2 = new CookieBind2Input( "key-sample2", "id_text2", "id_button2" );
	var text_cookie3 = new CookieBind2Input( "key-sample3", "id_text3", "id_button3" );

	if( text_cookie1.getValue() ){
		$("#id_text1").val( text_cookie1.getValue() );
	}
	$("#id_button1").click( function(){
		var text = $("#id_text1").val();
		text_cookie1.save( text );
		alert( text + "\r\nをcookieに保存しました" );
	})

	$("#id_clear").click( function(){
		text_cookie1.save( null );
		text_cookie2.save( null ); // スーパークラスのメソッド呼んでみる。
		text_cookie3.del();
		alert( "cookieを削除しました" );
	})
});
  
</script>
</head>
<body>
<form>
	<input id="id_text1"   type="text" style="width: 128;"></input>
	<input id="id_button1" type="button" value="保存1"></input>
	<br>
	<br>
	<input id="id_text2"   type="text" style="width: 128;"></input>
	<input id="id_button2" type="button" value="保存2"></input>
	<br>
	<br>
	<input id="id_text3"   type="text" style="width: 128;"></input>
	<input id="id_button3" type="button" value="保存3"></input>
	<br>
	<br>
	<input id="id_clear"   type="button" value="クッキー削除"></input>
</form>
</body>
</html>
```


# 補足
※１：ECMAScript5前提。IE11でも動くように。

※２：Google流 JavaScript におけるクラス定義の実現方法
　　　http://www.yunabe.jp/docs/javascript_class_in_google.html
　　　⇒ ほぉ！と思ったが、private化を「名前の末尾に _ を付ける」
　　　　名前規約で対応している所が、モヤモヤする。

※３：コンスタラクタで```return { mehotd1 : funcion() }```形式で
　　　メソッド定義すれば、praivateメンバ／メソッド利用し放題なのだが、
　　　それだとインスタンス生成（new）の度に、全てのメソッドの生成コスト
　　　が掛かる。せっかくのプロトタイプベースのJavaScriptでソレは、
　　　モヤモヤとする。　

※４：jquery.cookie.js は「cookieを手軽に扱えるようになるjQueryのプラグイン」。
　　　「jquery.cookie.jsの使用方法メモ」などを参照のこと。
　　　http://cly7796.net/wp/javascript/plugin-jquery-cookie/

※５：ちな、JavaScript のオブジェクト指向プログラミングの考え方は、
　　　公式のMozilla Developer Network のページが普通に分かり易くて
　　　驚いた。このページは、適宜読み返したいと思う。
　　　https://developer.mozilla.org/ja/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript