JSで可変長の配列を引数にして関数をコールする、の話し
一個前の記事( http://uzulla.hateblo.jp/entry/2011/11/18/190503 )について、可変長の配列を引数にして、関数をコールする必要があったので、そのときの会話などをメモ。
http://www.facebook.com/junichi.ishida/posts/10150466421723064?notif_t=like
前提として
function func(){ console.log(argument[0]) console.log(argument[1]) console.log(argument[2]) } func( 'a', 'b'. 'c' );
JSはこういう事ができる。ちょっとPerlっぽいな。
引数を明示しなくても、argumentという特殊な配列で(perlの@_みたい)値が取れる。
後、以下のコードはJSといいつつCoffeeScriptです。
まあ、同じ事できるから適当に脳内変換してください。
本題:ary = [A,B,C]; func(ary) と func(A,B,C) を等価にできないか
引数を可変で渡せる(関数の内部で、argumentsの配列で取れる)コードはよくみるんだが、
可変個の配列を渡して、可変個の引数を指定したように関数をコールするようなものをみたことがない。
(なんでこれが欲しいのかは、一つ前の記事をみてください)
なんでもかんでもObjectにつっこんで、それを渡したっていいのだけれど、コード量がふえないほうがいいなーっておもった。
個人的にはまず
if arguments.length == 0 @func() if arguments.length == 1 @func(arguments[0]) if arguments.length == 2 @func(arguments[0],arguments[1]) if arguments.length == 3 @func(arguments[0],arguments[1],arguments[2]) if arguments.length == 4 @func(arguments[0],arguments[1],arguments[2],arguments[3])
というダークサイドが思い浮かんだが、これはさすがにないなーという事でボツ。
次に、evalでつなぐのも手じゃないか?とおもったんですが、
args = [] for col,i in arguments args.push( "arguments["+i+"]" ); evalstr = "func(#{args.join(',')});"; eval( evalstr );
まあ、やっぱEvalとかどうかと思う。
どうやってやったらいいのかなーってなやんだら、すがわらさん*1が教えてくれた。
apply()を使え
http://www.tohoho-web.com/js/object.htm#inheritClass
http://d.hatena.ne.jp/chaichanPaPa/20080615/1213499529
どうやら本来は別の用途の様だが(その関数のスコープ内のthisを、自由に変更できる、実行している場所を変えられる)、そんなのはどうでもよくて、
func.apply(this, args)すると、まったく要望通りの事ができる!
function aaa(){ for(i=0; arguments.length>i; i++){ console.log(arguments[i]); } } aaa(1,2); // -> 12 aaa(1,2,3); // -> 123 ary = [1,2,3]; aaa.apply(this, ary); // -> 123 ary = [1,2,3,4,5]; aaa.apply(this, ary); // -> 12345
※上それっぽくないコードだったので、それっぽいコードに修正
すばらしい!
コレを使えば、可変長の引数をどんどんつかって、読みづらいコードが大量生産できますね!
Javaとかの人が泡を吹きます!
めでたしめでたし!
*1:上のFBリンクからたどると良い