JavaScriptのデフォルト引数とundefinedの考え方がよく分かっていなかった話
結論
関数の引数がデフォルト値を持つ場合、 undefined を渡すことはできないので、そういう設計をやめよう
サンプルコード
以下は Node.js 6 と Chrome 59 で確認した。
デフォルト引数がない場合
> function bar(abc) { console.log(abc) }
> bar(undefined)
undefined
デフォルト引数がある場合
> function foo(abc = null) { console.log(abc) }
> foo()
null
> foo(1)
1
> foo(undefined)
null
なんでこれに気づいたか
こんなコードを書いた。
bar(foo() || undefined)
function bar(name = null) {}
この場合、foo() の戻り値が false 相当の場合、bar() の中の name が undefined になることを期待していたが、実際にはそうはならなかった。
foo() || undefined
だけを評価した場合は foo() の戻り値が false 相当の際に期待通り undefined となる。
したがって、関数に渡ってくる部分での評価で undefined を受け取らないことになっているようだ。
ちなみに Babel で変換すると
var arg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : <default>;
になるので、あーそりゃ undefined 渡せませんよね、というのは分かります。
まとめ
- 本来 JavaScript の関数の引数に undefined を渡すことはできる
- ただし Node.js や ES2015 対応していてデフォルト引数を使える場合は渡せないような挙動になる
- そもそも undefined を渡すとはナニゴトだという設計の方が正しそうなので、そうしよう