JavaScriptの関数に引数が複数ある場合、オブジェクト形式にすると、値の意味がわかりやすくてとても便利です。
さらに、引数に初期値を設定してあげれば、関数の設定を変えたいときだけ引数を書けば良いので、より便利に関数を使うことができます。
const func = ({ hoge = 'foo' } = {}) => console.log(hoge);
func(); // 'foo'
func({ hoge: 'bar' }); // 'bar'
こんな感じ。
関数func()
の実引数を空にしたときは、コンソールログに文字列foo
が表示され、オブジェクト形式でhoge
プロパティの値を設定すると、そのプロパティ値が適用されるので、文字列bar
が表示されます。
便利ですね。
でも、なぜこのような挙動になるのでしょうか??
分割代入でオブジェクトの初期値を設定
const func = ({ hoge = 'foo' } = {}) => console.log(hoge);
上記関数の{hoge = 'foo'} = {}
部分は、分割代入の記法を使用しています。
分割代入のサンプルっぽく、引数の中身を独立させてみます。
const obj = {};
const { hoge = 'foo' } = obj;
// const { hoge = 'foo' } = {}; と同じ
console.log(obj.hoge) // undefined
console.log(hoge); // 'foo'
オブジェクトの分割代入では、左辺を{ hoge = 'foo' }
の形にすることで、初期値を設定できます。
また、右辺のオブジェクトのプロパティがundefined
の場合は、左辺の初期値が適用されるので、hoge
の値は文字列foo
になります。
もし、右辺のオブジェクトのプロパティに値があった場合は、そちらが適用されるので、以下のようにhoge
の値が文字列bar
になります。
const obj = { hoge: 'bar' };
const { hoge = 'foo' } = obj;
// const { hoge = 'foo' } = { hoge: 'bar' }; と同じ
console.log(obj.hoge) // 'bar'
console.log(hoge); // 'bar'
上記の内容を踏まえて、改めて関数を見てみましょう。
const func = ({ hoge = 'foo' } = {}) => console.log(hoge);
func(); // 'foo'
func({ hoge: 'bar' }); // 'bar'
実引数が空の場合は、仮引数の{ hoge = 'foo' } = {}
が適用され、hoge
が文字列foo
になります。
逆に、実引数にオブジェクトが指定されている場合、仮引数内は{ hoge = 'foo' } = { hoge: 'bar' }
の状態になるので、hoge
は文字列bar
になります。
ちなみに、仮引数の= {}
を消してしまうと、実引数が空のときに代入元のオブジェクトがなくなってしまうので、エラーになってしまいます。
const func = ({ hoge = 'foo' }) => console.log(hoge);
func(); // Uncaught TypeError
func({}); // 'foo'
func({ hoge: 'bar' }); // 'bar'
オブジェクトの分割代入に関して
ここからは余談ですが、オブジェクトの分割代入を少し掘り下げてみます。
const obj = {};
const { hoge = 'foo' } = obj;
console.log(obj.hoge) // undefined
console.log(hoge); // 'foo'
オブジェクトobj
のhoge
プロパティがundefined
の状態ということは、以下のように書き換えることができます。
const obj = { hoge: undefined };
const { hoge = 'foo' } = obj;
console.log(obj.hoge) // undefined
console.log(hoge); // 'foo'
さらに、左辺の{ hoge = 'foo' }
は、オブジェクトのプロパティとプロパティ値が同じだから省略されていると考えられるため、
const obj = { hoge: undefined };
const { hoge: hoge = 'foo' } = obj;
console.log(obj.hoge) // undefined
console.log(hoge); // 'foo'
こう書き換えることもできます。
hoge
ばっかりだと分かりづらいので、ちょっと変えてみます。
const obj = { hoge: undefined };
const { hoge: val = 'foo' } = obj;
console.log(obj.hoge) // undefined
console.log(val); // 'foo'
こうやってみると、プロパティ値の変数val
に、文字列foo
を代入しているようにみえますね。
つまり、オブジェクトの分割代入は、オブジェクトのプロパティ値を変数とし、そこに値を代入していると考えられるわけです。
const _val = 'foo';
const obj = { hoge: _val };
const val = obj.hoge;
console.log(val); // 'foo'
こんな感じで。
分割代入はなかなか理解しづらい記法ですが、こうやって紐解いてみるとわかりやすいですね。