ActionScript3.0で関数クロージャ使えると便利だよ!

ActionScriptでは、関数クロージャ使う場合と、使わない場合では、だいぶ書き方に差が出る。
関数クロージャ使った方が、綺麗に、短く書けるようになる。


ということで、メソッドクロージャ使ったパターンを紹介するよ!


関数クロージャってなに?っていう人は以下のサイトを読めばわかるかも。
Adobe ActionScript 3.0 * 関数のスコープ
メソッドクロージャとバインドメソッド at AS3S.ORG

その1 イベントのリスナーとして使う

イベントリスナーを作るとき、わざわざメンバとして作ってやるのはめんどくさい。
そんなときは関数クロージャ使えばいいよ!

普通に書いた場合

package 
{
	import flash.display.Sprite;
	import flash.events.Event;
	public class Main extends Sprite 
	{
		public function Main():void 
		{
			addEventListener(Event.ENTER_FRAME, onEnterFrame);
		}
		private function onEnterFrame(e:Event):void
		{
			trace("ENTER FRAME !");
		}
	}
}


関数クロージャを使用した場合

package 
{
	import flash.display.Sprite;
	import flash.events.Event;
	public class Main extends Sprite 
	{
		public function Main():void 
		{
			addEventListener(Event.ENTER_FRAME, function(e:Event):void {
				trace("ENTER FRAME !");
			});
		}
	}
}


関数クロージャを使えば結構コードがすっきりして、可読性が上がる。

その2 スコープとして使う

ASのスコープは関数単位。
Javaとは違ってブロック単位でのスコープはないよ。
つまり関数内では同じ変数を二個作ることは出来ないわけだ。
例えば関数内でfor文を二回以上使いたい場合、はループのための変数名を二個作るか、
変数を使いまわさないといけない。

public function Main():void 
{
	var xs:/*int*/Array = [];
	for (var i:int = 0; i < 5; i++ )
	{
		xs.push(i);
	}
	var sum:int = 0;
	for (var j:int = 0; j < xs.length; j++ )
	{
		sum += xs[j];
	}
	trace(sum);
}


この例だとiとjという2つの変数を使っている。
ただ、この書き方は、下のfor文で間違ってiを使ったりして、間違えやすい。


これを関数クロージャでくくってやると、スコープが働くので、
別々の関数クロージャなら同じ変数を宣言しても問題なくなる。

public function Main():void 
{
	var xs:/*int*/Array = [];
	(function():void{
		for (var i:int = 0; i < 5; i++ )
		{
			xs.push(i);
		}
	})();
	var sum:int = 0;
	(function():void{
		for (var i:int = 0; i < xs.length; i++ )
		{
			sum += xs[i];
		}
	})();
	trace(sum);
}


iを別々の場所で二回宣言しても、コンパイラに怒られることはない。

その3 配列の高階関数の引数として使う

例えば、配列の要素すべてに5を足した配列を作りたいとしよう。
普通にやるなら、for文で回すのが一般解だろう。

var xs:/*int*/Array = [0, 1, 2, 3, 4, 5];
var outs:/*int*/Array = [];
for (var i:int = 0; i < xs.length; i++)
{
	outs.push(xs[i] +5);
}
trace(outs);


しかし、配列にはそれにぴったりな関数が用意されてる。map()だ。

var xs:/*int*/Array = [0,1,2,3,4,5];
var outs:/*int*/Array = xs.map(
	function(x:int, index:int, xs:/*int*/Array):int { return x + 5; }
);
trace(outs);


ちなみにこれはもっと短く書ける。

trace([0, 1, 2, 3, 4, 5].map(function(x:int, ...rest):int { return x + 5; } ));


すっごい短く書けるよ!


配列には他にも、便利な関数が何個もある。
filter()とか、every()とか、some()とか。

ちなみに、map()とか、filter()とか、引数に関数をとる関数を高階関数っていうらしいよ。



関数クロージャ便利だからどんどん使っていこうぜ!


※追記
メソッド、メソッドクロージャ、関数クロージャ - 妄想宝箱