forEachによる回避

by 9re forked from イベントリスナの外にある変数を匿名関数で使いたい (diff: 17)
♥0 | Line 42 | Modified 2010-02-12 10:31:23 | MIT License
play

ActionScript3 source code

/**
 * Copyright 9re ( http://wonderfl.net/user/9re )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/xZaf
 */

// forked from masamunet's イベントリスナの外にある変数を匿名関数で使いたい
package {
    import flash.display.Sprite;
	import flash.display.Graphics;
	import flash.events.MouseEvent;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
    public class FlashTest extends Sprite {
        public function FlashTest() {
            var tf:TextField = new TextField;
			tf.autoSize = TextFieldAutoSize.LEFT;
			tf.text = "ここに数字が表示されます。";
			addChild(tf);
			//直径
			var radius:Number = 10.0;
			//横の間隔
			var marginWidth:Number = 5.0;
			//縦の間隔
			var marginHeight:Number = 15.0;
			//ボタンの数
			var l:int = 5;
			var arr:Array = [];
			for (var i:int = 0; i < l; i++) 
			{
				var sp:Sprite = createCircle(radius);
				sp.buttonMode = true;
				sp.x = ((sp.width + marginWidth) * i) + radius;
				sp.y = tf.height + marginHeight;
				arr.push(sp);
			}
			
			// この問題自体はループ内の一時変数をクロージャーが参照する時に生じる
			// 有名な問題ですね。
			// 一般にmap等の高階関数を利用することで、
			// 一時変数への参照を回避するというのもひとつの手です。
			// ループ内でクロージャーを生成しその場で評価するというのもありますが、
			// 結局はどれもが一時変数への参照を回避するという点では一緒です
			arr.forEach(function ($sprite:Sprite, $index:int, $arr:Array):void {
				addChild($sprite);
				$sprite.addEventListener(MouseEvent.CLICK, function ():void {
						tf.text = "このボタンナンバーは " + $index + "です。";
				});
			});
			
			//なぜならfor文を抜けたこの時点での変数iの中には5が入っているから。
			//(ボタンが押されてイベントリスナーが処理を始めるのは、時間的にみて
			// このコードよりももっと後なので、その時の変数iを探しにいってしまう)
        }
		private function createCircle(radius:Number = 10.0, color:uint = 0xFF0000):Sprite {
			var sp:Sprite = new Sprite();
			var g:Graphics = sp.graphics;
			g.beginFill(color);
			g.drawCircle(0, 0, radius);
			g.endFill();
			return sp;
		}
    }
}