ひよっこPGのブログ

主に、技術メモや英語たまにギター関連のことも書いているブログです。

クロージャを使ったフラグの切り替えサンプル

現在、自分は社内WEBシステムの スケジュール機能を作ってます。

それで スケジュールが 縦表示 横表示があって それの切り替えボタンを作ったときの 一部を紹介します

JavaScriptで、クロージャというものがあって グローバルオブジェクト汚さないように素人ながら考えて作りました。

では、ソースをどうぞ。

<!DOCTYPE html>
<HTML lang="ja">

<HEAD>
	<meta charset="UTF-8">
	<title>クロージャを使ったフラグの切り替え</title>

	<script type="text/javascript">

		var changeArea1 = function (){
			var flg = 1;
			return function(){
				if(flg === 1){
					document.getElementById( "area1" ).style.display = 'none';
					document.getElementById( "area2" ).style.display = 'block';
					flg = 2;
				}
				else if(flg === 2){
					document.getElementById( "area1" ).style.display = 'block';
					document.getElementById( "area2" ).style.display = 'none';
					flg = 1;
				}
			}
		}();

		var changeArea2 = function (){
			var flg = 1;
			return function(){
				if(flg === 1){
					document.getElementById( "area3" ).style.display = 'none';
					document.getElementById( "area4" ).style.display = 'block';
					flg = 2;
				}
				else if(flg === 2){
					document.getElementById( "area3" ).style.display = 'block';
					document.getElementById( "area4" ).style.display = 'none';
					flg = 1;
				}
			}
		}();
	</script>
</HEAD>

<BODY>

<h1>クロージャを使ったフラグの切り替え</h1><br>

<button onclick="changeArea1();">area1 と area2きりかえ</button>
<div id="area1">
	<font color="red">area1だよーーー</font>
</div>
<div id="area2" style="display: none;">
	<font color="blue">area2だよーーー</font>
</div>

<button onclick="changeArea2();">area3 と area4きりかえ</button>
<div id="area3">
	<font color="red">area3だよーーー</font>
</div>
<div id="area4" style="display: none;">
	<font color="blue">area4だよーーー</font>
</div>

</BODY>

</HTML>



area1だよーーー


area3だよーーー
このサンプルは、
area1 area2というDivボックスがありますが それをボタンを押すことで表示を切り替えるサンプルです。

area3 area4もありますがほぼ同じ処理で動いています。

このサンプルで自分が注目してほしいのは
どちらも フラグの変数名で flg という同じ変数名を使っている点です。
Javaに慣れていると {} で囲むとブロックスコープになって {}を抜けると変数が破棄されるものと考えちゃうんですが。

JavaScriptにはそもそもブロックスコープに対応していないんですよね。
なので

function changeArea1(){
  var flg = 1;
}
function changeArea2(){
  var flg = 2;
}

この二つの関数は、window.flg というプロパティを共有していることになります。


では、どのようにしたらJavaのようにローカル関数みたいに使えるのでしょう?

JavaScriptでは、関数内での定義は、関数スコープになります。
つまり、関数内の定義は、関数内のみで有効になるということです。

changeArea1()について説明してみます。

var changeArea1 = function (){
	var flg = 1;
	return function(){
		if(flg === 1){
			document.getElementById( "area1" ).style.display = 'none';
			document.getElementById( "area2" ).style.display = 'block';
			flg = 2;
		}
		else if(flg === 2){
			document.getElementById( "area1" ).style.display = 'block';
			document.getElementById( "area2" ).style.display = 'none';
			flg = 1;
		}
	}
}();

少しずつ分解します。

var changeArea1 = function(){
  return 1;
}();
console.log(changeArea1);
//=> 1

無名関数を宣言後、すぐに実行する。 なのでchangeArea1には 1が代入される。


次は

var flg = 1;
return function(){
	if(flg === 1){
		document.getElementById( "area1" ).style.display = 'none';
		document.getElementById( "area2" ).style.display = 'block';
		flg = 2;
	}
	else if(flg === 2){
		document.getElementById( "area1" ).style.display = 'block';
		document.getElementById( "area2" ).style.display = 'none';
		flg = 1;
	}
}

この部分ですが、無名関数内で定義するので flg変数は 無名関数内のみで有効です。
そのなかで flg変数を使った 関数を返す。 これでクロージャの完成。

var changeArea1 = function(){
	if(flg === 1){
		document.getElementById( "area1" ).style.display = 'none';
		document.getElementById( "area2" ).style.display = 'block';
		flg = 2;
	}
	else if(flg === 2){
		document.getElementById( "area1" ).style.display = 'block';
		document.getElementById( "area2" ).style.display = 'none';
		flg = 1;
	}
}

と同じことですが flgはこの関数内のみで有効になります。