JavaScriptの「何もない」の正体:undefinedとnullを使いこなすプロの流儀
現場でコードレビューをしていると、`if (value == null)` と書くべき場所で `if (!value)` と書いてバグを生んでいるシーンに遭遇することがよくある。あるいは、APIレスポンスの型定義で「とりあえず全部 `undefined` にしておこう」という安易な設計を見て、胸が痛むこともある。
JavaScriptにおいて `undefined` と `null` は、どちらも「値がない」ことを表す。しかし、その出自とセマンティクスは全くの別物だ。これを混同していると、バグの温床になるだけでなく、チームのコードの品格まで落ちてしまう。
今日は、この「永遠の二択」について、アーキテクトの視点から深掘りしてみよう。
—
1. `undefined` は「未定義」、`null` は「空の箱」
まず、この二つの歴史的背景を理解してほしい。
- `undefined`: JavaScriptの言語仕様が自動的に割り当てる値だ。変数宣言しただけで値が代入されていない時、関数の引数が渡されなかった時など、「まだ何も定義されていない」という状態を示す。これは「システム側の都合」に近い。
- `null`: プログラマが意図的に「ここには何もない」ことを示すために代入する値だ。オブジェクトが存在すべき場所に、明示的に「空っぽ」を置く。これは「人側の意思」だ。
ブラウザのエンジン(V8など)内部では、`undefined` は「まだ値が確定していない領域」として扱われるのに対し、`null` は「オブジェクトの参照先が存在しないことを示す具体的な値」としてメモリに保持される。これらは本質的に「未知(unknown)」と「無(nothing)」という違いがあるんだ。
2. 現場でやってはいけない「曖昧な比較」
よくあるのが、`==`(抽象等価演算子)を使った比較だ。
// これは「null または undefined」を判定する常套句だが、
// 意図が不明瞭になりがちだ
if (value == null) {
// 確かに動くが、チームメンバーが「意図的なnullチェック」なのか
// 「未定義の確認」なのかを読み解くコストが発生する
}
実務では、厳密等価演算子 `===` を使うのが絶対的な正義だ。これを使えば、`0` や `””`(空文字)、`false` といった「Falsyな値」との混同を確実に防げる。
3. 実践:どう使い分けるのが「美しい」のか?
僕が設計する際は、以下のルールをチームに徹底させている。
- 関数の戻り値やプロパティの初期値には `undefined` を使う: 「まだ値がない」という初期状態はJSのデフォルトに任せる。
- 「存在しないこと」を明示したい場合は `null` を使う: APIの結果として「該当するデータなし」を表現する場合など、ビジネスロジック上の意味を持つ「空」には必ず `null` を使う。
実践的なサンプルコード
以下のコードは、APIからユーザー情報を取得する際の典型的なパターンだ。そのままエディタに貼り付けて挙動を確認してみてほしい。
/
- ユーザー情報の取得をシミュレート
/
function fetchUser(id) {
// IDが不明な場合は明示的にnullを返す(意図的な空)
if (!id) return null;
// 何らかの処理がまだ終わっていない状態をシミュレート
return undefined;
}
const user = fetchUser(null);
// 1. nullチェック(意図的な空を判定)
if (user === null) {
console.log(“ユーザーIDが指定されていません。”);
}
// 2. undefinedチェック(未定義を判定)
if (user === undefined) {
console.log(“まだ通信中か、値が設定されていません。”);
}
// 3. 現場で最も安全なパターン(nullとundefinedを両方排除したい場合)
// 実務では「値が確実に存在する場合のみ処理する」ケースが多いため、
// nullでもundefinedでもないことを確認するのが賢い
if (user != null) {
// ここで初めて値に対する操作を行う
// 0や””を弾かないので非常に実用的
}
4. アーキテクトからのアドバイス
最後に、型安全を追求するなら TypeScript の活用は不可欠だ。
`tsconfig.json` の `strictNullChecks: true` を有効にすれば、`undefined` や `null` の混入をコンパイル時に検知できる。これによって、「ランタイムでいきなり `TypeError: Cannot read property ‘xxx’ of undefined` が発生する」という地獄のようなデバッグ作業から解放される。
結局のところ、`undefined` と `null` を使い分けるということは、「この値は、誰が管理しているのか?」という所有権と責任の所在を明確にすることに繋がるんだ。
コードを書くとき、常に「これはシステムが勝手に割り当てたものか? それとも僕が意図的に空にしたものか?」と自問自答してほしい。その一瞬の迷いが、堅牢なアプリケーションを作るための第一歩になるはずだ。
次は、この辺りの知識を活かして、Optional Chaining (`?.`) や Nullish Coalescing (`??`) とどう組み合わせていくか、といった話をしよう。現場のコードをクリーンに保つための、最高の武器になるはずだよ。

コメント