JavaScript
ECMAScript2015

【JavaScript】関数の引数をオブジェクト形式にして、さらに初期値を設定する。

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'

オブジェクトobjhogeプロパティが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'

こんな感じで。

分割代入はなかなか理解しづらい記法ですが、こうやって紐解いてみるとわかりやすいですね。