ActionScript3のスコープ
他の言語の癖でなにげなく、、、ではまってしまいがちなところ。
ActionScript3でのスコープは、functionによってのみつくられるとのこと。
ちゃんと意識しておかないとクロージャを使おうとしたときなどにハマりがち。
たとえば、
var array:Array = new Array(); for(var i:int=0; i<3; i++) { var obj:Object = {closure: function():void {log('index:'+i);}}; array.push(obj); } for each (var obj:Object in array) { obj.closure(); // index:0 index:1 index:2 と表示したい }
このスクリプトを実行したとき、ログには以下のように表示される。
index:3 index:3 index:3
forはスコープをつくらないため、クロージャobj.closureのスコープ=obj.closure()を実行した時点のスコープとなる。
これを回避して、期待どおりに動作させるには以下のようにする。
var array:Array = new Array(); for(var i:int=0; i<3; i++) { (function():void { // 無名関数をつくって var index:int = i; // 無名関数のスコープの変数に代入 var obj:Object = {closure: function():void {log('index:'+index);}}; array.push(obj); })(); // 呼び出す } for each (var obj:Object in array) { obj.closure(); // index:0 index:1 index:2 と表示される }
無名関数が評価されたあとも、そのスコープの環境は残ってて、クロージャはそのスコープで評価される。この、スコープを抜けた後も、スコープの環境自体は残ってるって性質のことを静的スコープ(レキシカルスコープ)という。