引数がたくさんあるときはオブジェクトにすると楽
この間、Javascriptを書いている時に、引数がたくさんある関数ができてしまいました。
通常、引数は渡した順番に代入されるので、数が多いと順番を守るのが大変になります。
そこで引数にオブジェクトを使うと、引数を順番ではなく名前で指定できるので間違えが少なくなります。
function test(obj){
console.log(obj.a , obj.b);
}
test({a:'hoge',b:'fuga'});
##結果
hoge fuga
オブジェクト引数でデフォルト値を付けると要素を省略できない
Javascriptでは関数の引数にデフォルト値を設定することができます。
引数を省略した時にはデフォルト値が使われるのでとても便利です。
function test( a = 1 ){
console.log(a);
}
test();
test(10);
##結果
1
10
引数をオブジェクトにした時もデフォルト値を設定することができます。
やってみました。 ただしこの場合には引数を完全に省略するか、すべての引数を指定する必要があります。
function test2( obj = { a:'A_default',b:'B_default' }){
console.log(obj.a,obj.b);
}
test2();
test2({a:'change',b:'modify'});
##結果
A_default B_default
change modify
引数としてオブジェクトの一部の要素だけを渡してもエラーにはなりませんが、渡さなかった引数はデフォルト値が設定してあってもUndefinedになります。
function test2( obj = { a:'A_default' , b:'B_default' }){
console.log( obj.a, obj.b );
}
test2();
test2({a:'change'});
##結果
A_default B_default
change undefined
デフォルト値をオブジェクト全体に対して設定しているので、当たり前と言えば当たり前なのですが、できれば一部の引数を省略した場合でもデフォルト値を有効にしたいところです。
オブジェクト引数の一部省略に対応する書き方
調べてみると、別の書き方をすれば一部の要素だけを渡しても、残りの要素にデフォルト値が設定されることがわかりました。
以下のように、{a:a='default'}
といった形でデフォルト値を設定します。
function test3({ a: a = 'A_default', b: b = 'B_default' }) {
console.log( a, b );
}
test3({ b:'Change' };
##結果
A_default Change
これには簡略化した書きかたもあるみたいです。選択代入の応用らしいのですが、正直よく分かりません。要素がたくさんある時には書くのがちょっと楽になりそうですね。
function test4({ a = 'A_Default', b = 'B_default' } = {}) {
console.log( a, b );
}
test4({ b:'Change' });
##結果
A_default Change
普通の引数とオブジェクト引数を組み合わせる
しかし、引数をひとつしか渡さないときにもオブジェクトを使う必要があるのは逆に面倒です。
ライブラリでよく見るfunction func(arg,{optional}){
みたいに、よく使う引数は普通の変数として渡して、たまに使うオプションだけオブジェクトで渡したいです。
で、試しにこんな書き方をしてみましたが、これは後ろのオブジェクト引数を省略できませんでした。
function test4( e = 10, { a: a = "A_default", b: b = "B_default" }) {
console.log(e);
console.log( a, b );
}
test4(100, { b: "Change" });
##結果
100
"A_default" "Change"
##エラー
test4(1);
test4();
スプレッド構文でオブジェクト引数とデフォルト値をマージする
引き続き調べていくと、やっぱり引数は普通に渡して、デフォルト値を関数内で設定する方が簡単らしいことが分かりました。
デフォルト値を設定する方法としてなるほどと思ったのが、デフォルト値をオブジェクトとして用意しておいて、引数とマージすることでした。
function test5(arg = 999, option) {
const defaultValues = { a: "A_default", b: "B_default" }; //デフォルト値を用意
let opt = { ...defaultValues, ...option }; //スプレッド構文を使ってオブジェクトをマージ。重複する要素は上書きされる
console.log(arg, opt);
}
test5();
test5(50);
test5(10, { b: 1000 });
999
"a": "A_default",
"b": "B_default"
50
"a": "A_default",
"b": "B_default"
10
"a": "A_default",
"b": 1000
この方法は以下のブログで知りました。大感謝。
スプレッド構文を使ってオブジェクトをマージすると重複する要素は上書きされるんですね。
let opt = { ...defaultValues, ...option };
//同名の要素があった場合、defaultValuesの内容がoptionの内容で上書きされる
自分はついつい「if文を使ってオブジェクト要素の有無をチェックして〜」みたいなアタマの悪い方法を使ってしまいがちなので、こういう書き方を見るとすごいなぁと思います。
この方法では、すべての引数を省略することも、一部の引数を省略することもできました。
どんなオブジェクトでも引数に使えますし、最も柔軟性があるのでこれを使っていこうと思います。