uzullaがブログ

uzullaがブログです。

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リンクからたどると良い