子供時代は痩せてたので口の悪い上級生から「ホネホネロック」とからかわれていましたが、その呼ばれ方、けっこう気に入ってました。正宗です。
JavaScriptでもActionScriptでも、関数を登録する場面ってけっこうよくあって、ActionScriptでいえば特にaddEventListenerですね。そんなときに引数を渡したい事もあると思うんです。
その方法を書いておきたいと思います。
jQuery(JavaScript)の場合
jQuery( '#hogehoge' ).load( 'nanika.html', myFunc );
function myFunc() {
alert( 'こんにちは' );
}
こういうやつのmyFuncに引数を渡したいとき。
jQuery( '#hogehoge' ).load( 'nanika.html', myFunc( 'こんにちは' ) );
function myFunc( argment ) {
return function(){
alert(argment);
}
}
渡され先でreturn functionするのがコツです。コツなのです!
ActionScriptの場合
どんどんいきましょう
_mc.addEventListener( MouseEvent.CLICK, __click__( 'クリックされたよ' ) );
functioin __click__( argment ):Function {
return function( e:MouseEvent ):void {
trace( argment );
}
}
Progressionの場合
こういう書き方が出来るってことはProgressionのaddCommand内でも使えるはず!
new SerialList( null,
myFunc( 'コマンドにFunctionを登録するときにも引数がわたせる' ),
myFunc( 'どんどん渡そう' )
);
function myFunc( argment ):Function {
return function():void{
trace( argment );
}
}
何故こうなるの?
書き方だけわかっても、理屈がわからないと気持ち悪いですよね。一見意味不明な書き方にも見えるし、まる覚えしないと次もういちど書けないようでは身につけたとは言えません。
僕なりに解釈した考え方を書いていこうと思います。
ちなみに型が明記できるActionScriptで書いていきます。
function は()で実行される
function myFunc( ) {
trace( 'hogehoge' );
}
//関数を実行
myFunc( );
当たり前のルールなんですが、一度作った関数は、その関数の名前のお尻に() 「括弧」を付ける事で実行されます。
ということは逆に言うと括弧を付けないと実行されないという事です。
関数を実行せずとりあえず登録だけしておく
function myFunc( e:MouseEvent ) :void {
trace( 'クリックされました' );
}
_mc.addEventListener( MouseEvent.CLICK, myFunc );
こういう書き方をしている場合、ようは「マウスクリックされたときにmyFuncっていう関数を実行してね」と書いている訳です。
_mc.addEventListener( MouseEvent.CLICK, myFunc() ); //まちがい
こう書いちゃうと、マウスクリックの時に実行してほしい関数なのに今実行してしまいます。
つまり、「あとで実行したい関数は、名前だけ登録しておく」のが正解なわけで、通常はそう書いている訳ですね。
関数の「戻り値」をおさらいしよう
本来関数を登録だけしておくはずの場所で、あえて実行する訳ですから通常だとエラーなわけです。間違いです。そこをあえて実行してみた場合、スクリプトの世界ではどのような事が行われるでしょうか。
その謎を考える前に関数の「戻り値」というやつをもう一回おさらいしてみます。
function myFunc1( ) :int {
return 100;
}
var a:int = myFunc1( ); //変数aには数字の100が入る
function myFunc2( ) :String {
return "こんにちは";
}
var b:String = myFunc2( ); //変数bには文字の「こんにちは」が入る
function myFunc2( ) :Object {
return { test:"ごはんおいしいです" };
}
var c:Object myFunc3( ); //変数cにはObjectが入る
関数が関数を返す
結論から言うと、イベントリスナーやコールバック関数など、「関数を今実行せず登録だけしておく」場所で「あえて実行させてみる」わけですから、そこで実行された関数が関数を返してしまえばいい、とある頭のいい誰かが考えた訳ですね。
function myFunc( ) :Function {
return function( ) { trace( 1+1 ); };
}
var f:Function = myFunc( ); //変数fに関数が入る
f( ); //関数が実行され1+1の計算結果が表示される
たとえばイベントリスナーの第二引数には
function ( e:Event) :void { }
この形が入れば言い訳ですから、
function myFunc( ) :Functioin {
return function ( e:Event) :void { };
}
こういう形を返す関数を作っておいて
_mc.addEventListener( Event.ENTER_FRAME, myFunc( ) );
こういうふうにイベントリスナーの登録時にはmyFuncを実行してしまえば、関数が返ってくるので、その返ってきた関数のほうをイベントリスナーは登録してくれる、というのがこの書き方の謎の正体です。
はじめに発見した人はそうとう頭良いと思います。ぼくはこの理屈を発見したとき芸術性すら感じました。
実用性もさることながら、こういった動作の合理性を考えていくのもかなり楽しいです。昔中学校の技術の時間にエンジンの仕組みを勉強して以来、その動作の合理性に魅せられて車オタクバイクオタクというよりはエンジンオタクになったのを思い出します。
「リスナー関数が使う値を外から指定する」というノートを書きました。ご参考まで。
http://www.fumiononaka.com/TechNotes/Flash/FN1007002.html
野中さん、ありがとうございます!
確かにかなり癖があって、特にASでは使いどころが難しい(というか使いどころがそんなにない)みたいですね。
僕自身まだ理解の途中でまとめた記事なので、ものすごくためになりました!
jQuery使ってるときに、そこの名前空間の縛りがきつかったので、
みたいな感じで、コールバック関数内でthisが違ってくるので何とかしてthisをmyFunctionとして扱って欲しくて、頭が爆発しそうになりながらこの方法を試してみたのでした(苦笑)。
で、ついでにどうしてこうなるのか理解したくて、型指定できるAS3で考えてみたわけですが、野中さんの記事をよく読むと確かに通常AS3でこういうやり方はおすすめできませんね。
「リスナー関数に(引数というよりは)外部から値を渡す」「関数クロージャー」なども含めて僕がよくわかっていなかった点が見えてきて、いっそう深い理解のきっかけになりました!重ね重ねありがとうございます!!