Flexでfor eachのなかでfunctionを作る落とし穴

というわけで、以前よりFlvプレーヤーを作っていたんですけども、ちょっと落とし穴にはまったのでメモ。
というわけでいきなり、検証用コード。

Asf.mxml

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
		creationComplete="init()">
	<mx:Script source="AsfAction.as"/>
	<mx:TextArea id="log" />
</mx:Application>

AsfAction.as

private var added:Array;

public function init():void
{
	added = new Array();

	var source:Array = ["test1", "test2", "test3"];

	for each(var i:String in source) {
		added.push(function():void{
				trace(i);
				});
	}

	for each(var f:Function in added) {
		f();
	}
}

test.rb

added = []

["test1", "test2", "test3"].each {|i|
	added.push(Proc.new {
		p i
	})
}

added.each {|pr|
	pr.call
}

つまり、いったんfor eachの中でfunctionを生成し、それをそのループの外で実行するというもの。

で、ActionScriptではまるのがこの部分。for eachの中でfunctionを生成した場合の挙動はこんな感じ。

ruby
test1
test2
test3

ActionScript
test3
test3
test3

見てのとおり、Rubyではfunctionが生成された時点での値を保持するのに対して、ActionScriptでは生成時に渡された変数名を保持しています。
ですので、値が「test1」のときに生成されたfunctionが実行されるときに初めて値を参照するため、「test3」が出力されてしまいます。

というわけで、ある個別の変数に値を入れることで回避することができます。
つまり別のクラスでいったん保持するということです。
というわけで、3つのファイルに分割しました。

Asf.mxml

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
		creationComplete="init()">
	<mx:Script source="AsfAction.as"/>
	<mx:TextArea id="log" />
</mx:Application>

AsfAction.as

import Hoge;

private var added:Array;

public function init():void
{
	added = new Array();

	var source:Array = ["test1", "test2", "test3"];

	for each(var i:String in source) {
		var hoge:Hoge = new Hoge();
		hoge.strhoge = i;
		added.push(hoge);
	}

	for each(var f:Hoge in added) {
		f.call(log);
	}
}

Hoge.as

package{
	
	import mx.controls.*;
	
	public class Hoge
	{
		public var strhoge:String;
		
		public function call(log:TextArea):void
		{
			log.text += strhoge;
		}
	}
}

で実行結果。

test1test2test3

めでたしめでたし。