JavaScript の OR演算子で未定義を回避する記述はヤバいのでメモる
JavaScript 界隈でよくみかける
const a = _a || 555 // OR演算子で未定義を回避する記述
という記述。なんかヤバい感じがしていたので確認したら案の定だったので、メモしておきます。
推測するに、「引数 _a が undefined だったら、デフォルト値 555 を入れておく」という操作を一行で完結に書いている。
しかし、0
や ''
や当然 false
も未定義(undefined)と同じ判定になるので、このコードはヤバい。
確認コード
let html = ''
function arg_undef_test( a1, a2, a3, a4, a5, a6, a7, a8 )
{
html += `<div>a1: 456 -> ${ a1 || 123 }</div>` // -> 456 OK
html += `<div>a2: true -> ${ a2 || 123 }</div>` // -> true OK
html += `<div>a3: false -> ${ a3 || 123 }</div>` // -> 123 NG 期待は false
html += `<div>a4: -1 -> ${ a4 || 123 }</div>` // -> -1 OK
html += `<div>a5: 0 -> ${ a5 || 123 }</div>` // -> 123 NG 期待は 0
html += `<div>a6: null -> ${ a6 || 123 }</div>` // -> 123 NG 期待は null
html += `<div>a7: '' -> '${ a7 || 123 }'</div>` // -> '123' NG 期待は ''
html += `<div>a8: undefined -> ${ a8 || 123 }</div>` // -> 123 OK まぁ期待した動きにはなるんだけど、、、
html += '<hr>'
const undef = ( _a, _b ) => ( _a === undefined ? _b : _a )
html += `<div>a1: 456 -> ${ undef( a1, 123 ) }</div>` // -> 456 OK
html += `<div>a2: true -> ${ undef( a2, 123 ) }</div>` // -> true OK
html += `<div>a3: false -> ${ undef( a3, 123 ) }</div>` // -> false OK
html += `<div>a4: -1 -> ${ undef( a4, 123 ) }</div>` // -> -1 OK
html += `<div>a5: 0 -> ${ undef( a5, 123 ) }</div>` // -> 0 OK
html += `<div>a6: null -> ${ undef( a6, 123 ) }</div>` // -> null OK
html += `<div>a7: '' -> '${ undef( a7, 123 ) }'</div>` // -> '' OK
html += `<div>a8: undefined -> ${ undef( a8, 123 ) }</div>` // -> 123 OK
}
arg_undef_test(
456, // a1
true, // a2
false, // a3
-1, // a4
0, // a5
null, // a6
'' // a7
)
// class member undef test ----
const boo = {
f1: 456,
f2: true,
f3: false,
f4: -1,
f5: 0,
f6: null,
f7: '',
}
html += '<hr>'
html += `<div>f1: 456 -> ${ boo.f1 || 123 }</div>` // -> 456 OK
html += `<div>f2: true -> ${ boo.f2 || 123 }</div>` // -> true OK
html += `<div>f3: false -> ${ boo.f3 || 123 }</div>` // -> 123 NG 期待は false
html += `<div>f4: -1 -> ${ boo.f4 || 123 }</div>` // -> -1 OK
html += `<div>f5: 0 -> ${ boo.f5 || 123 }</div>` // -> 123 NG 期待は 0
html += `<div>f6: null -> ${ boo.f6 || 123 }</div>` // -> 123 NG 期待は null
html += `<div>f7: '' -> '${ boo.f7 || 123 }'</div>` // -> '123' NG 期待は ''
html += `<div>f8: undefined -> ${ boo.f8 || 123 }</div>` // -> 123 OK
html += '<hr>'
const undef = ( _a, _b ) => ( _a === undefined ? _b : _a )
html += `<div>f1: 456 -> ${ undef( boo.f1, 123 ) }</div>` // -> 456 OK
html += `<div>f2: true -> ${ undef( boo.f2, 123 ) }</div>` // -> true OK
html += `<div>f3: false -> ${ undef( boo.f3, 123 ) }</div>` // -> false OK
html += `<div>f4: -1 -> ${ undef( boo.f4, 123 ) }</div>` // -> -1 OK
html += `<div>f5: 0 -> ${ undef( boo.f5, 123 ) }</div>` // -> 0 OK
html += `<div>f6: null -> ${ undef( boo.f6, 123 ) }</div>` // -> null OK
html += `<div>f7: '' -> '${ undef( boo.f7, 123 ) }'</div>` // -> '' OK
html += `<div>f8: undefined -> ${ undef( boo.f8, 123 ) }</div>` // -> 123 OK
document.body.innerHTML = html
#実行結果
解説
まとめ
面倒でも、未定義を確認するコードを一行。
const undef = ( _a, _b ) => ( _a === undefined ? _b : _a )
書こうよ。>おれもな
追記 Null合体(??) を教えていただきました🙏
||
を ??
に置き換えればよいという、、、スグレモノ。なぜ、いままで知らなかったのか。>反省
let html = ''
function arg_undef_test( a1, a2, a3, a4, a5, a6, a7, a8 )
{
html += `<div>a1: 456 -> ${ a1 || 123 }</div>` // -> 456 OK
html += `<div>a2: true -> ${ a2 || 123 }</div>` // -> true OK
html += `<div>a3: false -> ${ a3 || 123 }</div>` // -> 123 NG 期待は false
html += `<div>a4: -1 -> ${ a4 || 123 }</div>` // -> -1 OK
html += `<div>a5: 0 -> ${ a5 || 123 }</div>` // -> 123 NG 期待は 0
html += `<div>a6: null -> ${ a6 || 123 }</div>` // -> 123 NG 期待は null
html += `<div>a7: '' -> '${ a7 || 123 }'</div>` // -> '123' NG 期待は ''
html += `<div>a8: undefined -> ${ a8 || 123 }</div>` // -> 123 OK まぁ期待した動きにはなるんだけど、、、
html += '<hr>'
html += `<div>a1: 456 -> ${ a1 ?? 123 }</div>` // -> 456 OK
html += `<div>a2: true -> ${ a2 ?? 123 }</div>` // -> true OK
html += `<div>a3: false -> ${ a3 ?? 123 }</div>` // -> false OK
html += `<div>a4: -1 -> ${ a4 ?? 123 }</div>` // -> -1 OK
html += `<div>a5: 0 -> ${ a5 ?? 123 }</div>` // -> 0 OK
html += `<div>a6: null -> ${ a6 ?? 123 }</div>` // -> 123 NGってか ?? は期待どおり OK
html += `<div>a7: '' -> '${ a7 ?? 123 }'</div>` // -> '' OK
html += `<div>a8: undefined -> ${ a8 ?? 123 }</div>` // -> 123 OK
}
arg_undef_test(
456, // a1
true, // a2
false, // a3
-1, // a4
0, // a5
null, // a6
'' // a7
)
// class member undef test ----
const boo = {
f1: 456,
f2: true,
f3: false,
f4: -1,
f5: 0,
f6: null,
f7: '',
}
html += '<hr>'
html += `<div>f1: 456 -> ${ boo.f1 || 123 }</div>` // -> 456 OK
html += `<div>f2: true -> ${ boo.f2 || 123 }</div>` // -> true OK
html += `<div>f3: false -> ${ boo.f3 || 123 }</div>` // -> 123 NG 期待は false
html += `<div>f4: -1 -> ${ boo.f4 || 123 }</div>` // -> -1 OK
html += `<div>f5: 0 -> ${ boo.f5 || 123 }</div>` // -> 123 NG 期待は 0
html += `<div>f6: null -> ${ boo.f6 || 123 }</div>` // -> 123 NG 期待は null
html += `<div>f7: '' -> '${ boo.f7 || 123 }'</div>` // -> '123' NG 期待は ''
html += `<div>f8: undefined -> ${ boo.f8 || 123 }</div>` // -> 123 OK
html += '<hr>'
html += `<div>f1: 456 -> ${ boo.f1 ?? 123 }</div>` // -> 456 OK
html += `<div>f2: true -> ${ boo.f2 ?? 123 }</div>` // -> true OK
html += `<div>f3: false -> ${ boo.f3 ?? 123 }</div>` // -> false OK
html += `<div>f4: -1 -> ${ boo.f4 ?? 123 }</div>` // -> -1 OK
html += `<div>f5: 0 -> ${ boo.f5 ?? 123 }</div>` // -> 0 OK
html += `<div>f6: null -> ${ boo.f6 ?? 123 }</div>` // -> 123 OK いいね
html += `<div>f7: '' -> '${ boo.f7 ?? 123 }'</div>` // -> '' OK
html += `<div>f8: undefined -> ${ boo.f8 ?? 123 }</div>` // -> 123 OK
document.body.innerHTML = html
(あらら、 Qiita のシンタックスハイライトが ?? に追従できていない感)
で、「オプショナルチェイニング演算子 (?.) 」なるものを知る。なんじゃこりゃー。あとで調べる。