遅延制御の作用・副作用
以下のコードを実行すると、どうなるでしょうか。
function hoge( str ){
trace( str + " called by " + arguments.caller );
}
function callhoge(){
setTimeout( hoge, 1000, "hello");
}
this.callhoge();
arguments.caller は自身を呼んだ関数を参照するので、callhoge を参照してるんだなと思ったら大間違いで、callhoge は1秒後に hoge を呼ぶように setTimeout で遅延処理を登録しただけなんですよね。
実際に呼んでいるのは、どこの誰とも分からないシステム中枢。
もうひとつ、騙されやすいのが以下のコード。
function hoge( str ){
trace( this + ": " + str );
}
setTimeout( this.hoge, 1000, "hello");
1秒後にメソッドを呼んでいるんだなと思いがちで、実際その通りなんだけどスコープが違います。
この場合、メソッド hoge 内での this の参照先は存在せず undefined になりますが、以下のような呼び出し方をすれば問題ありません。
setTimeout( this, "hoge", 1000, "hello");
これはおそらく1秒後に内部的に
this["hoge"].apply( this, "hello");
と呼んでいるのでしょう。
たとえば、呼び出される前にメソッド hoge の内容を書き換えるとどうなるかというと
setTimeout( this.hoge, 1000, "hello");
this.hoge = function(){
trace("hoge");
}
--> 書き換え前の hoge() が実行される
setTimeout( this, "hoge", 1000, "hello");
this.hoge = function(){
trace("hoge");
}
--> 書き換え後の hoge() が実行される
前者はメソッドの参照を直接渡しているので実行に至るまで全く影響を受けませんが、後者はあくまで実行時にメソッドを参照するので影響受けまくリング。
むしろメソッドを未定義なままで遅延登録しても、実行時までに定義すればいいというちょっと便利な仕様。
これらの挙動を何かに応用できないかと考えてみたけれど、明らかにバグの温床になるようなところなので何もしない方がいいでしょう。合掌。