Caution
お使いのブラウザはJavaScriptが実行できない状態になっております。
当サイトはWebプログラミングの情報サイトの為、
JavaScriptが実行できない環境では正しいコンテンツが提供出来ません。
JavaScriptが実行可能な状態でご閲覧頂くようお願い申し上げます。
JavaScript
応用編
- トップページ
- JavaScript応用編 - 引数と可変長引数とargumentsについて
引数と可変長引数とargumentsについて
みなさまどうも。続きまして引数とか『可変長引数』(かへんちょうひきすう)とか『arguments』(アーギュメンツ)とかについてやっていきましょう
まずJavaScriptにおいての引数の挙動について軽く確認していきます。JavaScriptの引数はかなり自由に構築することができ、引数の個数も特に意識する必要なく使用することができます。
以下のサンプルを見てください。
var f = function(x, y, z){ console.log(x); console.log(y); console.log(z); }; f(1, 2, 3); // 数値『1』、『2』、『3』が出力されます。
上記のサンプルは仮引数の『x』、『y』、『z』を出力するだけの簡単な処理ですね。
3つの引数を出力する関数となっていますが、規定数以下の引数を渡して実行させても、逆に規定数以上の引数を渡して実行させてもエラーにはなりません。
何も受け取らない引数には『undefined』が入っているものとして処理されます。
var f = function(x, y, z){ console.log(x); console.log(y); console.log(z); }; f(1, 2, 3); // 数値『1』、『2』、『3』が出力されます。 f(1, 2, 3, 4); // 数値『1』、『2』、『3』が出力されます。 f(1, 2); // 数値『1』、『2』、『undefined』が出力されます。
JavaScriptの引数の挙動についてはこんな感じになります。
続いて『可変長引数』についてです。
『可変長引数』とは個数が変動する引数のことで『可変引数』、『可変個引数』とも呼ばれます。イメージとしては「個数の決まっていない引数そのものを指す単語」といった感じになりますね。
例えば「引数に渡ってきた全ての値を出力する処理」を作りたい、となると『可変長引数』を使って実装することになります。
そしてJavaScriptで引数全てを取得する場合は『arguments』というオブジェクトを使用します。
これは関数内で使用できるオブジェクトで、関数に渡された全ての引数を『arguments』で取得できますので、さきほどの「引数に渡ってきた全ての値を出力する処理」なんかを構築する場合は以下のような感じになります。
var f = function(){ for(var i = 0; i < arguments.length; ++i){ // 関数実行時に引数として渡されたものは『arguments』で参照できます。 console.log(arguments[i]); } }; // 引数に渡したもの全てをそれぞれ出力します。 f(0); f(0, 1); f(0, 1, 2); f(0, 1, 2, 3);
上記のように第1引数から順番に『arguments』の要素として参照できます。なので、例えば第一引数を参照したい場合は『arguments[0]』と記述すればOKです。
var f = function(){ console.log(arguments[0]); // 第1引数を出力します。 }; f(0); // 数値『0』が出力されます。 f(1); // 数値『1』が出力されます。 f(2); // 数値『2』が出力されます。 f(3); // 数値『3』が出力されます。
引数の数を固定した上で処理を進めたいといった場合は『arguments.length』を使用して下さい。これで引数の個数が取得できます。
var f = function(){ if(arguments.length !== 3) return; // 引数の数が3つじゃない場合はreturnします。 console.log("クリア"); }; f(0); f(0, 1); f(0, 2, 3); // 文字列『クリア』が出力されます。
関数定義の『()』の中に『a, b, c, d,...』というように永遠と仮引数を書き続けるわけにもいきませんので『可変長引数』を使用する処理を構築する場合は『arguments』の使用は必須になりますね。
var f = function(a, b, c, d,...){ // 仮引数を永遠と書き続けるのは不可能です。 };
『可変長引数』を使用して構築した関数は『可変長引数関数』や『varargs関数』(バーアーグス関数)と呼ばれることがあります。
たまに参考書とかで出てくる程度の使用頻度ですが念のため覚えておきましょう。
では続いて『arguments』の使用の際の注意点を確認していきましょう。
まず『arguments』は添字配列っぽいですが通常の配列でない、ということがあげられます。
前回の記事でも解説しましたが『arguments』は『ArrayLikeオブジェクト』という通常の添字配列っぽい形をした謎なオブジェクトになってます。
つまり、『Array.prototype』の共有はありませんので通常の添字配列で使用できるメソッドとかが使用できません。
もし通常の添字配列に用意されてるメソッドとかを『arguments』に対して使用したい、となった場合は『call()』や『apply()』を使ってメソッドを呼び出してしまいましょう。
var f = function(){ console.log(Array.prototype.join.call(arguments)); // 通常の添字配列になりすました『arguments』で『join()』します。 }; f(1, 2, 3); // 文字列『1,2,3』が出力されます。
このように『aruguments』に対して『call()』や『apply()』を使って通常の添字配列のメソッドを使用する、というテクニックは良く使用されるので覚えておいて下さい。
※『call()』と『apply()』の解説はこちらへどうぞ。
続いて『aruguments』の各要素に代入することで引数を上書きすることができちゃいます。以下のような感じですね。
var f = function(x){ console.log(x); // 第1引数を出力します。 arguments[0] = "ワンパンマン"; // arguments[0]を上書きします。 console.log(x); // 第1引数が上書きされて文字列『ワンパンマン』が出力されます。 console.log(arguments[0]); // 文字列『ワンパンマン』が出力されます。 }; f(0); // 数値『0』が出力されたあとに文字列『ワンパンマン』が2回出力されます。
JavaScript以外の言語で『可変長引数』を参照する場合は呼び出しのみで上書き不可となっている事が多いです。
しかし、JavaScriptの場合は上記のようにさくっと上書きできちゃったりしますので他の言語に精通してる方は気をつけて下さい。
尚、『strictモード』(厳格モード)で実行すると上書き処理は不可になります。以下のような感じですね。
"use strict"; // 『strictモード』で実行します。 var f = function(x){ console.log(x); // 第1引数を出力します。 arguments[0] = "ワンパンマン"; // arguments[0]を上書きします。 console.log(x); // 『strictモード』なので引数が上書きされず、第1引数が出力されます。 console.log(arguments[0]); // 文字列『ワンパンマン』が出力されます。 }; f(0); // 数値『0』が2回出力された後に文字列『ワンパンマン』が出力されます。
こちらも覚えておきましょう。
その他にも通常の状態と『strictモード』とで大きな違いがあり、通常の状態では『arguments』本体を上書きすることができちゃいます。
var arguments = null; // グローバル変数『arguments』を定義します。 console.log(arguments); // 『null』が出力されます。 var f = function(){ var arguments = null; // 『arguments』を上書きします。これでこの関数内での『可変長引数』の参照はできなくなります。 console.log(arguments); // 『null』が出力されます。 }; f(); // 『null』が出力されます。
しかし、『strictモード』では『arguments』が予約語となっているので、『arguments』を上書きしようとするとちゃんと怒られます。
"use strict"; // 『strictモード』で実行します。 var arguments = null; // グローバル変数『arguments』を定義しようとするとちゃんとエラーとなります。
"use strict"; // 『strictモード』で実行します。 var f = function(){ var arguments = null; // 『arguments』を上書きしようとするとちゃんとエラーとなります。 };
注意点についてはこんな感じですね。
そして、『arguments』には『arguments.callee』という自身の関数オブジェクトを参照することができる便利なプロパティが用意されているのでそちらも紹介しておきます。
ちょっとした再帰的処理に使用されることが多いですね。以下がサンプルです。
var x = 0; // グローバル変数『x』を定義します。 var f = function(){ console.log(x); // グローバル変数『x』を出力します。 ++x; // グローバル変数『x』をインクリメントします。 if(x < 10) arguments.callee(); // グローバル変数『x』が10未満の場合に自身の関数を実行します。 }; f(); // 『0』から『9』までの数値が出力されます。
使い方は上記のような感じで、『arguments.callee()』と記述すれば自身の関数が実行できます。
んでもって『arguments.callee』は無名関数でも問題なく自身を呼び出せます。以下が無名関数な即時関数のサンプルになります。
var x = 0; // グローバル変数『x』を定義します。 (function(){ // 『0』から『9』までの数値が出力されます。 console.log(x); // グローバル変数『x』を出力します。 ++x; // グローバル変数『x』をインクリメントします。 if(x < 10) arguments.callee(); // グローバル変数『x』が10未満の場合に自身の関数を実行します。無名関数でもOKです。 })();
こんな感じで無名関数でも『arguments.callee』を使って自身を呼び出せるので覚えておくと良いかもしれません。
(´-`).。oO(まあ、無名関数の場合は名前がないので再帰的処理を構築するとなると...)
(´-`).。oO(『arguments.callee』を使用する以外の方法はなかったりしますのであしからず...)
『arguments.callee』は古い時代から存在しているため全てのブラウザで実行することができます。
しかし、最近は『arguments.callee』が非推薦になっていますので、再帰的処理を構築するならば自身の関数名を使って呼び出すようにしたほうが良いかもしれません。
こんな感じですね。
var x = 0; // グローバル変数『x』を定義します。 var f = function(){ console.log(x); // グローバル変数『x』を出力します。 ++x; // グローバル変数『x』をインクリメントします。 if(x < 10) f(); // グローバル変数『x』が10未満の場合に自身の関数を関数名から呼び出して実行します。 }; f(); // 『0』から『9』までの数値が出力されます。
即時関数で『arguments.callee』を使わずに再帰的処理を行いたい場合は自身の即時関数に名前を付けてしまいましょう。
var x = 0; // グローバル変数『x』を定義します。 (function f(){ // こんな感じで即時関数に『f』という名前を付けちゃえば関数内で自身を呼び出す事ができます。 console.log(x); // グローバル変数『x』を出力します。 ++x; // グローバル変数『x』をインクリメントします。 if(x < 10) f(); // グローバル変数『x』が10未満の場合に自身の関数を関数名から呼び出して実行します。 })();
上記のように名前を付けてしまえば即時関数で再帰的処理を構築することができます。
あと『arguments.callee』は『strictモード』で実行させることはできませんのでご注意下さい。
"use strict"; // 『strictモード』で実行します。 (function(){ arguments.callee(); // エラーとなります。 })();
JavaScriptでは関数定義するときに名前を付けた関数を渡したり、名前を付けた関数を即時実行させたりすることができます。
var f = function _f(){ // 『_f』という名前を付けた関数オブジェクトを渡します。 }; (function f1(){ })();
イメージとしては『function(){}』という関数オブジェクトの部分だけが渡されたり即時実行されているような感じになります。
そして、上記の『_f』と『f1』はちゃんとローカルスコープとなっているのでグローバル汚染は発生しません。
var f = function _f(){ // 『_f』という名前を付けた関数オブジェクトを渡します。 }; (function f1(){ })(); f(); // 実行できます。 _f(); // エラーです。 f1(); // エラーです。
主に使用される目的としては先ほど解説した『arguments.callee』を使用せずに再帰的処理を構築する場合になりますね。
JavaScriptならではのトリッキーな記述方法になりますが、結構使われるパターンになるので覚えておくと良いかもしれません。
というわけで以上になります。次の記事では『strictモード』について色々とやっていきたいと思います。
ではこの辺で。失礼致します。
この記事は桜舞が執筆致しました。
著者が愛する小型哺乳類 |
桜舞 春人 Sakurama HarutoISDN時代から様々なコンテンツを制作しているちょっと髪の毛が心配な東京在住のプログラマー。生粋のロングスリーパーで、10時間以上睡眠を取らないと基本的に体調が悪い。好きなだけ寝れる生活を送るのが夢。ゲームとスポーツと音楽が大好き。誰か髪の毛を分けて下さい。 |
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。