概要
無名関数とは
を先に参照してください。
を先に参照してください。
前回でも説明したとおり、ActionScriptでは無名の関数を作ることが出来ます。
プログラム
var str:String = "ActionScript";
var f:Function = function():void { trace(str); };
f(); // ActionScript
ここで注目して欲しいのは2行目です。
この2行目が実行された段階では"ActionScript"が出力されるとは確定していません。
この2行目が実行された段階では"ActionScript"が出力されるとは確定していません。
var str:String = "ActionScript";
var f:Function = function():void { trace(str); };
str = "Flash"
f(); // Flash
関数を実行する前にstrの中身を書き換えると、"ActionScript"ではなく"Flash"と出力されます。
このように、「実際に関数を実行した時点」でのstrの中身が出力されるわけです。
このように、「実際に関数を実行した時点」でのstrの中身が出力されるわけです。
もう一つサンプルを見てみましょう。
var f:Function;
for (var i:int = 0; i < 5; i++)
{
if (i == 3) f = function():void { trace(i); }
}
f();
5回ループする内、iが3のときだけ、iを出力する無名関数を代入します。
f()で実行してみると3ではなく5と出力されます。
f()で実行してみると3ではなく5と出力されます。
これは先ほどのサンプルと同じ理由で、関数が実行された時点ではループは回りきっているのでiの値が5になっているからです。
対策
実際に実行される時点ではなく、無名関数を書いた時点での値を参照したい場合があります。
その対策方法を考えてみましょう。
その対策方法を考えてみましょう。
別の変数を作る
for (var i:int = 0; i < 5; i++)
{
if (i == 3)
{
var temp:int = i;
f = function():void { trace(temp); }
}
}
f(); // 3
特定時点での変数の中身を出力させたいなら、値を別の変数に保存するという方法があります。
高階関数
for (var i:int = 0; i < 5; i++)
{
if (i == 3)
{
f = (function(i:int):Function { return function():void { trace(i); } } )(i);
}
}
f(); // 3
無名関数を別の無名関数で囲い、引数を渡す形にするという方法もあります。
trace(i)はループ変数iではなく、新しく追加した外側の無名関数iを参照するので問題ありません。
trace(i)はループ変数iではなく、新しく追加した外側の無名関数iを参照するので問題ありません。
ライブラリの場合
BetweenAS3やProgressionのSerialListで無名関数を扱う場合について解説します。
分からない方は飛ばしてください。
分からない方は飛ばしてください。
BetweenAS3
var t:ITween;
for (var i:int = 0; i < 5; i++)
{
if (i == 3)
{
t = BetweenAS3.func(function(i:int):void { trace(i); }, [i]);
}
}
t.play(); // 3
BetweenAS3.funcで関数を指定できますが、第二引数でその関数の引数を渡すことが出来るので、そのままiを渡してコピーしてあげればいいです。
こうすれば、trace(i)のiはループ変数ではなく、引数で渡したiの方を参照することになります。
こうすれば、trace(i)のiはループ変数ではなく、引数で渡したiの方を参照することになります。
SerialList
var list:SerialList = new SerialList();
for (var i:int = 0; i < 5; i++)
{
if (i == 3)
{
list.addCommand(new Func(function(i:int):void { trace(i); }, [i]));
}
}
list.execute(); // 3
SerialListでも同じように、Funcの第二引数にiを渡すだけです。
検証用コード
package
{
import flash.display.Sprite;
import jp.progression.commands.Func;
import jp.progression.commands.lists.SerialList;
public class Main extends Sprite
{
public function Main()
{
var list:SerialList = new SerialList();
for (var i:int = 0; i < 5; i++)
{
if (i == 3)
{
list.addCommand(new Func(function(i:int):void { trace(i); }, [i]));
}
}
list.execute();
}
}
}
このwikiの更新情報RSS