【JavaScript】オブジェクトの存在チェックの方法アイデア

# 背景
JavaScriptを書いていて、オブェクトが存在しないうちに要素を参照してエラーになってしまう。そういった事態を避けるためには、存在チェックをする必要があります。今回は、バグ修正を行う中で存在チェックの方法について調べたので、それらの方法と使うべき場面について私見を述べます。

:::note
選択肢の根拠となったJavaScriptの仕様等について最初に書きます。結論から早く見たい！という方は[判定方法アイデア](#判定方法アイデア)からどうぞ
:::

:::note warn
すべてのパターンを網羅したわけではないので、あくまでもアイデアとして活用していただけると幸いです
:::

# 目次
- [前提](#前提)
    - [falsy（偽値）](#falsy偽値)
    - [論理積](#論理積)
    - [等価演算子と厳密等価演算子](#等価演算子と厳密等価演算子)
- [判定方法アイデア](#判定方法アイデア)
    - 1.[`undefined`との比較](#1-undefinedとの比較)
    - 2.[`undefined`がfalsyであることを利用](#2-undefinedがfalsyであることを利用)
    - 3.[オプショナルチェーンを利用](#3-オプショナルチェーンを利用)
- [まとめ](#まとめ)

# 前提となるJavaScriptの仕様
## falsy（偽値）
JavaScriptでは、条件文や繰り返し文などの場面で、強制的に論理型に型変換して偽となる値(falsy)という概念があります。以下はMDNに書かれているfalsyのリストです。
>- `null`
>- `undefined`
>- `false`
>- `NaN`
>- `0`
>- `-0`
>- `0n`
>- `""`
>- `document.all`
参照：[Falsy (偽値) - MDN Web Docs 用語集: ウェブ関連用語の定義 | MDN](https://developer.mozilla.org/ja/docs/Glossary/Falsy)

つまり、`undefined`は条件文では`false`として扱われ、文を簡潔にできます。
## 論理積
論理積は、一組の論理型のオペランドがすべて`true`であるときに`true`、それ以外`false`を返す演算子です。また、
>一般的には、この演算子は左から右に向けて評価した際に最初の偽値のオペランドに遭遇したときにはその値を、またはすべてが真値であった場合は最後のオペランドの値を返します。
参照：[論理積 (&&) - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Logical_AND)

とあります。つまり左側の式が`false`になる場合右の式は実行されないということになります。こちらも分岐を減らし簡潔なコードを書くために有用だと思いました。

## 等価演算子と厳密等価演算子
JavaScriptには等価演算子(`==`)と厳密等価演算子(`===`)があります。MDNによる両者の説明をChat-GPTにまとめてもらうと、
>等価演算子 (==) は、オペランドの型が異なる場合に自動で型変換を行い、その結果を比較します。
例えば、数値と文字列を比較するときには文字列が数値に変換されます。
一方、厳密等価演算子 (===) は型変換を行わず、オペランドの型が異なる場合には必ず false を返します。
これが両者の最も大きな違いです。等価演算子 (==) は型の違いを無視して比較するのに対し、厳密等価演算子 (===) は型まで含めて厳密に比較します。

今回は、オブジェクトが`null`になる可能性がない、とした上で`undefined`になる判定を行うとしました。オブジェクトが`null`になる可能性がある場合は、厳密比較を用いればそれぞれを判定することが可能と思います。

# 判定方法アイデア
今回バグ修正をしたコードは
```javascript:修正前コードのイメージ
if(object.property) {
```
です。これでは存在チェックなしに`object`の`property`にアクセスしているので読み込めずエラーになります。
## 1. `undefined`との比較
```javascript:undefinedとの比較
if(object !== undefined && object.property) {
```
今回考えた選択肢の中で一番冗長ですが、逆に読んだ人が意図を一番理解しやすいものでもあります。左の式はobjectが`undefined`の場合のみ`false`になり、右の式が見られないためエラーは発生しません。あえて厳密比較を採用したのは2.と差別化するためであり、通常の比較でも問題なく動作します。
## 2. `undefined`がfalsyであることを利用
```javascript:undefinedがfalsyであることを利用
if(object && object.property) {
```
今回の中では一番バランスがいい書き方かと思います。1に比べると意図は理解しづらいですが、シンプルに記述できるのがよいと思います。ただ`object`の中身が`undefined`以外のfalsyの値であったときにも条件に当てはまるので、それを別で検出したい場合は違う方法がよいかと思われます。

:::note
**TIP : 二重否定について**
```javascript:二重否定
if(!!object && object.property) {
```
とすると、二重否定という表現になります。JavaScriptの論理否定演算子`!`は、結果を反転するだけでなく、falsyの値を明示的に論理型に変換することができます。つまり、二重否定を用いることで、`truthy`は`true`に、`falsy`は`false`に明示的に変換をすることができます。
（今回は論理型が求められているわけではないので正直必要ないですが、調べていて論理型が必要な時使えるなと思ったので、ご参考までに...）
:::

## 3. オプショナルチェーンを利用
```javascript:修正後コードのイメージ
if(object?.property) {
```
`?.`の書き方はES2020から追加されたオプショナルチェーンという方法で、
>参照が`null`または`undefined`の場合にエラーとなるのではなく、式が短絡され`undefined`が返される
参照：[オプショナルチェーン (?.) - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Optional_chaining)

のだそうです。つまり、`undefined`かチェックするだけならこれで十分ということになります。
ただこの書き方はES2020から追加された記述であるため、それ以前のバージョンでは適用ができないので注意が必要です。

# まとめ
選択肢をいくつか書きましたが、プロジェクトの関係やバージョンの関係によって導入できるもの、できないものや、時々で適切なものが変わってくると思います。そうしたときの判断基準となる部分としてこちらの情報を生かしていただけると幸いです。