JavaScript の OR演算子で未定義を回避する記述はヤバいのでメモる


# JavaScript の OR演算子で未定義を回避する記述はヤバいのでメモる

JavaScript 界隈でよくみかける

```JS
    const a = _a || 555     // OR演算子で未定義を回避する記述
```

という記述。なんかヤバい感じがしていたので確認したら案の定だったので、メモしておきます。

推測するに、「引数 _a が undefined だったら、デフォルト値 555 を入れておく」という操作を一行で完結に書いている。
しかし、`0` や `''` や当然 `false` も未定義(undefined)と同じ判定になるので、このコードはヤバい。

# 確認コード

```JS
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
```

#実行結果

<p class="codepen" data-height="265" data-theme-id="dark" data-default-tab="html,result" data-user="yamazaki3104" data-slug-hash="zYNKOpZ" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="JavaScript OR演算子（||）は使ってはいけない"></p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

# 解説

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/undefined

# まとめ

面倒でも、未定義を確認するコードを一行。

```JS
const undef = ( _a, _b ) => ( _a === undefined ? _b : _a )
```

書こうよ。＞おれもな

# 追記 Null合体(??) を教えていただきました🙏

`||` を `??` に置き換えればよいという、、、スグレモノ。なぜ、いままで知らなかったのか。＞反省

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_operator

```JS
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 のシンタックスハイライトが ?? に追従できていない感）

で、「オプショナルチェイニング演算子 (?.) 」なるものを知る。なんじゃこりゃー。あとで調べる。