JavaScriptの特殊値（null,undefined,NaN,booleanのtrueとfalse）の判定

# はじめに
特殊な値の扱いについて整理する。
単純だけど覚えていないと不具合の元になりやすいので重要な情報。

# nullの判定
```javascript
// 値の比較
console.log(undefined == undefined);          // 出力: true
console.log(undefined === undefined);         // 出力: true
```

# undefinedの判定
```javascript
// 値の比較
let v;
console.log(v == void 0);                     // 出力: true
console.log(typeof v === 'undefined');        // 出力: true
```
```javascript
// 「undefined」はローカルスコープで再定義可能
// 再定義時に単純な「==」「===」だと意図しない比較になる
const undefined = 1; // 「undefined」の再定義
let v;
console.log(v);                               // 出力: undefined
console.log(v == undefined);                  // 出力: true (再定義の影響を受けない)
console.log(undefined == undefined);          // 出力: true (再定義値(= 意図しない値)の比較)

console.log(v === undefined);                 // 出力: false (再定義の影響を受ける)
console.log(undefined === undefined);         // 出力: true (再定義値(= 意図しない値)の比較)
```

# NaN(Not-a-Number)の判定
```javascript
// 値の比較（NaN同士の比較はできない）
console.log(NaN == NaN);                      // 出力: false
console.log(NaN === NaN);                     // 出力: false

// 値の比較（isNaNなら判定できる）
console.log(isNaN(NaN));                      // 出力: true
console.log(Number.isNaN(NaN));               // 出力: true
```

# nullとundefinedの違い
- 値
  - nullは明示的に設定する値
  - undefinedは暗黙的に設定される（変数が初期化されていないなど）

- 型
```javascript
// プリミティブ型"null"が"object"になるのは初期から存在するJavascriptのバグらしい
console.log(typeof null);                   // 出力: "object"
console.log(typeof undefined);              // 出力: "undefined"
```

- 等価性
  「undefined」の再定義を考慮すると以下の記載になる。
  ただし、「==」と「===」でも問題にはならない。
  「==」：true、「値がいない」意味は変わらず再定義の影響を受けない
  「===」：false、再定義されても型が違うことは変わらず再定義の影響を受けない
```javascript
// どちらも「値がない」ことを示すので特別に等しいと見なされる
console.log(null == void 0);                // 出力: true
// 厳密な比較では型が異なるため等しくない
console.log(typeof null === typeof void 0); // 出力: false
```



# NaNの補足
- 値
  - 数値演算が失敗したときに設定される（例えば、0除算(1 ÷ 0)）

- 型
```javascript
// 数字演算が失敗しているので"number"になる
console.log(typeof NaN); // 出力: "number"
```


# booleanのtrue（truthy）とfalse（falsy）の考え方
「動的型付け（Dynamic Typing）」なので様々な型で判定が可能。
特殊値の扱いや「静的型付け（Static Typing）」では実施できない判定に注意する。

```javascript
// 論理
console.log(false ? '' : 'falsy');            // 出力: falsy
console.log(true ? 'truthy' : '');            // 出力: truthy

// 数字
console.log(0 ? '' : 'falsy');                // 出力: falsy
console.log(1 ? 'truthy' : '');               // 出力: truthy
console.log(42 ? 'truthy' : '');              // 出力: truthy

// 特殊
console.log(null ? '' : 'falsy');             // 出力: falsy
console.log(undefined ? '' : 'falsy');        // 出力: falsy
console.log(NaN ? '' : 'falsy');              // 出力: falsy

// 文字列
console.log("" ? '' : 'falsy');               // 出力: falsy
console.log("0" ? 'truthy' : '');             // 出力: truthy
// 文字列（数字に変換すればfalsy）
console.log(Number("0") ? '' : 'falsy');      // 出力: falsy
console.log("1" ? 'truthy' : '');             // 出力: truthy
console.log("Hello" ? 'truthy' : '');         // 出力: truthy

// シンボル（利用ニーズなし）
console.log(Symbol() ? 'truthy' : '');        // 出力: truthy

// 配列（利用ニーズなし）
console.log([] ? 'truthy' : '');              // 出力: truthy

// オブジェクト（利用ニーズなし）
console.log({} ? 'truthy' : '');              // 出力: truthy

function alwaysTrue() {
  return true;
}
function alwaysFalse() {
  return false;
}
function noReturn() {}

// 関数（戻り値の定義で変わる）
console.log(alwaysTrue() ? 'truthy' : '');    // 出力: truthy
console.log(alwaysFalse() ? '' : 'falsy');    // 出力: falsy
console.log(noReturn() ? '' : 'falsy');       // 出力: falsy
```