Stackの実装とイベント設定サンプルコード

動的生成版と関数定義版2つのスタイルで実装してみた。

動的生成版のほうがJavaScriptっぽい。
しかしwindow.onloadの定義がぶくぶくと太っていくのが、気になる。

関数定義版のほうが関数一つ一つは小さくて見通しが良い。
しかしグローバル空間を汚さないように、全体を匿名関数で囲んでいるため、
結局ネストの深さとしては余り差がないかな。


html.js 動的生成版

'use strict';

// Stack サンプル
// 画面固有コード

// 画面ロードイベント登録
window.addEventListener('load', function() {
	var i, length;
	var stack = [];	// Stackテーブル

	// エレメントを取得
	var slctStack = document.getElementById('slctStack');
	var btnPush = document.getElementById('btnPush');
	var btnPop = document.getElementById('btnPop');
	var txtPush = document.getElementById('txtPush');
	var txtPop = document.getElementById('txtPop');
	var pDump = document.getElementById('pDump');

	// セレクトボックスオプション数だけ、Stack生成
	length = slctStack.length;
	for (i = 0; i < length; i++) {
		stack[i] = new Stack.Stack();
	}

	// セレクトボックスのonchangeイベント登録
	slctStack.addEventListener('change', function (evt) {
		// pタグに対してスタックダンプ
		pDump.innerHTML = stack[slctStack.selectedIndex].Dump();
		// txtPush, txtPopクリア
		txtPush.value = '';
		txtPop.value = '';
	}, false);
	
	// Pushボタンのonclickイベント登録
	btnPush.addEventListener('click', function (evt) {
		// txtPushの値取得
		var value = txtPush.value;

		// セレクトボックス選択インデックス取得
		i = slctStack.selectedIndex;

		if (value) {
			// 操作対象スタックにプッシュ
			stack[i].Push(txtPush.value);

			// txtPushにfocusして選択状態にする。
			txtPush.focus();
			txtPush.select();

			// pタグに対してスタックダンプ
			pDump.innerHTML = stack[i].Dump();
		}
	}, false);
	
	// Popボタンのonclickイベント登録
	btnPop.addEventListener('click', function (evt) {
		// セレクトボックス選択インデックス取得
		i = slctStack.selectedIndex;

		// 操作対象スタックからポップして、txtPopに設定
		if (txtPop.value = stack[i].Pop()) {
			// pタグに対してスタックダンプ
			pDump.innerHTML = stack[i].Dump();
		}
	}, false);
}, false);

html.js 関数定義版

'use strict';

// Stack サンプル
// 画面固有コード

// 匿名関数内でクロージャ生成
(function() {
	var elem = {};		// エレメント保持オブジェクト
	var stackTbl = [];	// Stackテーブル
	var stack;			// 操作対象スタック

	// 画面ロードイベントハンドラ
	window.addEventListener('load', init, false);

	// 画面ロード時初期化
	function init(evt) {
		var i, length;
	
		// エレメントを取得
		elem.slctStack = document.getElementById('slctStack');
		elem.btnPush = document.getElementById('btnPush');
		elem.btnPop = document.getElementById('btnPop');
		elem.txtPush = document.getElementById('txtPush');
		elem.txtPop = document.getElementById('txtPop');
		elem.pDump = document.getElementById('pDump');

		// セレクトボックスオプション数だけ、Stack生成
		length = elem.slctStack.length;
		for (i = 0; i < length; i++) {
			stackTbl[i] = new Stack.Stack();
		}

		// 初期の操作対象スタックをセレクトボックス選択中に合わせる
		stack = stackTbl[elem.slctStack.selectedIndex];
	
		// セレクトボックスのonchangeイベントに登録
		elem.slctStack.addEventListener('change', chngSlct, false);
		// Pushボタンのonclickイベントに登録
		elem.btnPush.addEventListener('click', clkPush, false);
		// Popボタンのonclickイベントに登録
		elem.btnPop.addEventListener('click', clkPop, false);
	}

	// セレクトボックス変更イベントハンドラ
	function chngSlct(evt) {
		// 操作対象スタックをセレクトボックスの
		// インデックスに対応するものに変更
		stack = stackTbl[elem.slctStack.selectedIndex];

		// pタグに対してスタックダンプ
		elem.pDump.innerHTML = stack.Dump();
		// txtPush, txtPopクリア
		elem.txtPush.value = '';
		elem.txtPop.value = '';
	}

	// Pushボタンクリックイベントハンドラ
	function clkPush(evt) {
		// txtPushの値取得
		var value = elem.txtPush.value;

		if (value) {
			// 操作対象スタックにプッシュ
			stack.Push(elem.txtPush.value);

			// txtPushにfocusして選択状態にする。
			elem.txtPush.focus();
			elem.txtPush.select();

			// pタグに対してスタックダンプ
			elem.pDump.innerHTML = stack.Dump();
		}
	}

	// Popボタンクリックイベントハンドラ
	function clkPop(evt) {
		// 操作対象スタックからポップして、txtPopに設定
		if (elem.txtPop.value = stack.Pop()) {
			// pタグに対してスタックダンプ
			elem.pDump.innerHTML = stack.Dump();
		}
	}
})();	// 即呼び出し

stack.js

'use strict';

// Stack サンプルコード
var Stack;

if (Stack) {
	// Stackは定義済み
	if (typeof Stack != 'object') {
		// Stackがobjectではない→正体不明のStack
		// 例外を投げる。
		throw new Error('Stack already exists but not object!');
	}
} else {
	// 名前空間オブジェクト生成
	Stack = {};
}


// 匿名関数内で処理
// Nodeを外部から隠し、Stackのみが操作するため
(function() {
	// ノードコンストラクタ
	function Node(value) {
		this.value = value;
		this.next = null;			// ひとまずnullを設定しておく
	}

	// Stackコンストラクタ
	Stack.Stack = function() {
		this.stack = new Node(null);
	};

	// 引数の値をpushする。
	Stack.Stack.prototype.Push = function(value) {
		var node = new Node(value);
		
		// スタックに積む
		node.next = this.stack.next;
		this.stack.next = node;
	};

	// stackからpopした値を返す。
	Stack.Stack.prototype.Pop = function() {
		var node = this.stack.next;
		var rtn;
		
		if (node) {
			// 先頭要素をスタックから切り離す。
			this.stack.next = node.next;
			rtn = node.value;
		} else {
			// ノード無しのばあい、nullを返す。
			rtn = null;
		}
		
		return rtn;
	};

	// stackをdumpした文字列を返す
	Stack.Stack.prototype.Dump = function() {
		var rtn = '';
		var node;
		
		for (node = this.stack.next; node; node = node.next) {
			rtn += node.value + '<br />';
		}
		
		return rtn;
	};

})();	// 即呼び出し

stack.html

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <meta http-equiv="Content-Script-Type" content="text/javascript">
    <title>Stack Sample</title>
    
    <!-- Stackモジュールロード -->
    <script src="./stack.js"></script>
    <!-- html依存コード定義 -->
    <script src="./html.js"></script>
  </head>
  
  <body>
    <!-- スタックセレクタ -->
    <select id="slctStack">
      <option>stack0</option>
      <option>stack1</option>
      <option>stack2</option>
    </select><br>
  
    <!-- 入力ボックス Pushボタン -->
    <input type="text" id="txtPush">
    <button id="btnPush">Push</button><br>
    
    <!-- 出力ボックス Popボタン -->
    <input type="text" id="txtPop" readonly>
    <button id="btnPop">Pop</button>
    
    <!-- Stack Dump用カンバス -->
    <p id="pDump">Stack Dump</p>
  </body>

</html>