松山事務所の石丸です。
あるところにログ種別、フォーマット文字列、可変長のパラメータを受け取る みんなの大好きな printf
のようなログ出力関数がありました。
それをそのまま使ってもいいのですが、ログ種別 “warning” を何度も間違えずに書く自信がないおじさんは、ログ種別毎に関数を用意しました。
関数名にしてしまえばIDEの支援が受けられて補完が効くし、参照も拾ってくれますよね。
1
2
3
4
5
6
7
8
9
10
11
|
function writeLog(type, format, var_args) {
// フォーマットしてログ出力
}
function warningLog(format, var_args) {
writeLog("warning", format, var_args);
}
function errorLog(format, var_args) {
writeLog("error", format, var_args);
}
|
いまにも動き出しそうですが、最後の引数 var_args は名前の雰囲気が可変長なだけで、ただの1つの引数でしかありません。
どうすればerrorLog関数やwarningLog関数からwriteLog関数へ可変長引数を伝えることができるのでしょうか?
そもそもどうやって可変長引数にアクセスするのか
可変長引数にアクセスするためには arguments
を使います。
arguments は、関数へ渡された引数に対応する Array のようなオブジェクトです。
Arrayのようなオブジェクト arguments
に配列のようにアクセスしてみます。
1
2
3
4
5
6
7
|
function errorLog(format, var_args) {
alert(arguments[0]); // %s %d %s
alert(arguments[1]); // arg1
alert(arguments[2]); // 2
}
errorLog("%s %d %s", "arg1", 2, "arg3");
|
arguments
には呼び出し元から渡されたパラメータがすべて入っているので、第1引数のフォーマット文字列まで取れてしまいます。
もちろん普段と同じように format や var_args でも arguments[0]、arguments[1]と同じ値が参照できます。
どうやってargumentsを渡すのか
可変長引数にアクセスする方法はわかりましたが、errorLog関数からwriteLog関数へどのように可変長引数を渡すのか。
1
2
3
|
function errorLog(format, var_args) {
writeLog("error", arguments);
}
|
と書いてしまいそうですが、arguments
はただの配列のようなオブジェクトでしかないので、
この書き方では”error”と arguments
2つのパラメータでwriteLog関数を呼び出しただけになってしまいます。
writeLog関数の中で arguments
を見てみると次のような形で渡されていました。
1
2
3
4
5
6
7
8
9
|
{
"0": "error",
"1": {
"0": "%s %d %s",
"1": "arg1",
"2": 2,
"3": "arg3"
}
}
|
次のようなフラットな形で渡したいですよね。
1
2
3
4
5
6
7
|
{
"0": "error",
"1": "%s %d %s",
"2": "arg1",
"3": 2,
"4": "arg3"
}
|
配列のようなオブジェクトをパラメータに関数を呼び出すにはFanction.applyを使用します。
Function.prototype.apply() – JavaScript | MDN
arguments
をただ引き渡すだけなら
1
2
3
|
function errorLog(format, var_args) {
writeLog.apply(this, arguments);
}
|
でいいのですが、今回はログ種別も渡したい。
でもapplyは thisArg
と argsArray
2つのパラメータしか受け取ってくれません。
最終的には次のようになりました。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
function writeLog(type, format, var_args) {
// フォーマットしてログ出力
}
function warningLog(format, var_args) {
Array.prototype.unshift.call(arguments, "warning");
writeLog.apply(this, arguments);
}
function errorLog(format, var_args) {
Array.prototype.unshift.call(arguments, "error");
writeLog.apply(this, arguments);
}
errorLog("%s %d %s", "arg1", 2, "arg3");
|
arguments
の先頭にログ種別を差し込んでapplyです。
use strict だと arguments
の上書きが出来ないらしいので、argumentsをsliceしてからunshiftですかね。
もっとエレガントでクールな方法があったら教えてください。ガムあげます。
追記
ES2015以降ならスプレッド構文でクールにかけるぜ!
とイケメンからアドバイスをいただきました。
1
2
3
|
function errorLog(format, var_args) {
writeLog(format, 'error', ...arguments);
}
|
良いですね!ガムあげます。