【実務・中級編】 undefinedとnullのセマンティクス – JavaScript実践ガイド

おい、調子はどうだい?
最近、コードレビューをしていて気になったんだが、お前らのコード、`undefined` と `null` をなんとなく雰囲気で使い分けてやしないか?

「とりあえずエラーが出ないから `null` 入れておきました」とか、「値が入ってないからどっちでも一緒っしょ」なんて思っているなら、今日の話をよく聞いてくれ。この2つの使い分けは、単なる好みの問題じゃない。フロントエンドのコードベースの「意図」を語らせるための、極めて重要なセマンティクス(意味論)なんだ。

今回は、JavaScriptの深淵を覗きつつ、実務で明日から即座に使えるプロの境界線引きを伝授しよう。

—

1. そもそも仕様としての `undefined` と `null` の決定的な違い

まずは、この二つがJavaScriptのエンジン内部や仕様書(ECMAScript)でどう定義されているか、その「出自」から整理しておこう。ここを理解すると、なぜ使い分ける必要があるのかが腹落ちするはずだ。

`undefined`: 「まだ値が割り当てられていない」というシステム都合の欠損

`undefined` は、JavaScriptのエンジンが「おい、ここにはまだ何も代入されてないぞ」と自動的に放り込む値だ。
例えば、変数を宣言しただけの中身や、関数の引数が渡されなかったときのデフォルト値、オブジェクトに存在しないプロパティにアクセスしたときなどはすべてこれになる。

要するに、「初期化の未完了」や「存在しないこと」をシステムが検知した状態を指す。

`null`: 「意図的に値が存在しない」という人間都合の不在

一方で `null` は、エンジンが勝手に使うことは絶対にない。「ここには値が存在しない(空である)」ということを、開発者がコード上で明示的に表現するための値だ。

typeof演算子を使うと `null` が `”object”` と返ってくる有名なバグ(仕様の歴史的負債)があるが、そんなものは忘れよう。セマンティクスとして、`null` は「意図的な無」なのだ。

—

2. ブラウザの裏側:V8エンジンはどう処理しているか?

少しだけ低レイヤーの話をしよう。私たちが書いたJavaScriptを実行するGoogle ChromeのV8エンジンなどのモダンJSエンジンは、メモリ効率を最大化するために死ぬほど最適化を行っている。

変数が `undefined` の状態と、何らかの値が入っている状態、そして `null` が入っている状態では、エンジンの内部的な隠しクラス(Hidden Class / Shapes)の遷移や、インラインキャッシュの効き方に違いが出てくる。
特に、オブジェクトのプロパティを後から追加したり削除したり、あるいは `undefined` で初期化したりすると、エンジンの最適化が外れて「辞書モード(遅いモード)」に落ち込むことがある。

実務においてパフォーマンスを語るなら、「最初から不要なプロパティを生やさない、あるいは必要な場合は `null` でスロットを確保して形状を安定させる」というテクニックが、大規模アプリケーションでは効いてくるんだ。まぁ、まずは「システム都合か、人間都合か」のセマンティクスを完全に守るのが先決だがね。

—

3. 実務における使い分けのガイドライン(決定版)

じゃあ、現場でどう使い分けるべきか。迷ったらこのルールに従ってくれ。チーム全員がこの共通認識を持てば、コードレビューでの無駄な議論が驚くほど減るはずだ。

ガイドラインのまとめ

  • `undefined` を使うべきケース
  • 変数が宣言されたが、まだ値が代入されていないとき(システムに任せる)
  • 関数の引数が省略されたとき
  • オifters(オブジェクト)のプロパティが存在しないことを確認する場合
  • `null` を使うべきケース
  • 「以前は値があったが、リセットされて今は何もない」状態を表現するとき
  • APIからのレスポンスで、データが存在しないことを明確に示す場合(JSONの仕様上、`undefined` はシリアライズできないので、必然的に `null` になる)
  • DOM要素が見つからなかったときの返り値(例: `document.getElementById(‘not-exist’)` は `null` を返す)

—

4. 現場ですぐに使える!実践コードパターン

百聞は一見に如かずだ。実際のフロントエンド開発でよくあるユースケースを例に、綺麗なコードの書き方を見ていこう。

/

  • ユーザープロフィールを更新する関数の例
  • セマンティクスを意識した undefined と null の使い分け

/
class UserProfileManager {
constructor(initialData = {}) {
// ユーザーが未入力の項目はシステム都合の「未定義」として扱う
this.bio = initialData.bio;

// 以前は設定されていたが、現在は明示的にクリアされた(空っぽ)データは null
this.avatarUrl = initialData.avatarUrl !== undefined ? initialData.avatarUrl : null;
}

/

  • プロフィール情報を部分更新する
  • @param {Object} updateData

/
update(updateData) {
// bio がオブジェクトに含まれていない(undefined)場合は、既存の値を維持する
if (updateData.bio !== undefined) {
this.bio = updateData.bio;
}

// avatarUrl に明示的に null が渡された場合は、画像を削除(クリア)したと解釈する
if (updateData.avatarUrl !== undefined) {
this.avatarUrl = updateData.avatarUrl; // null が入ることもある
}
}

isAvatarSet() {
// ここで Boolean(this.avatarUrl) とすると、
// null や undefined の両方を弾けるが、明確にチェックしたい場合は厳密等価演算子を使う
return this.avatarUrl !== null && this.avatarUrl !== undefined;
}
}

// — 使用例 —
const manager = new UserProfileManager({ bio: ‘フロントエンドが好きです’, avatarUrl: ‘https://example.com/avatar.png’ });

// アバター画像を削除する(意図的な「無」の代入なので null を使う)
manager.update({ avatarUrl: null });

console.log(manager.avatarUrl); // 出力: null
console.log(manager.bio); // 出力: ‘フロントエンドが好きです’ (更新されていないので維持される)

罠にハマるな! `nullish coalescing` (`??`) と `logical OR` (`||`) の違い

おまけとして、実務で最もよくやらかすミスについても触れておこう。
値が `undefined` または `null` のときだけデフォルト値をフォールバックさせたい場合は、`||` ではなく、Null合体演算子(`??`)を使え。

const userConfig = {
timeout: 0, // 0ミリ秒という「有効な値」を設定したいとする
};

// ❌ 良くない例: 0 は Falsy な値なので、意図せずデフォルト値に書き換わってしまう
const timeout1 = userConfig.timeout || 3000;
console.log(timeout1); // 出力: 3000 (あれっ!?)

// ⭕ 良い例: undefined または null のときだけフォールバックする
const timeout2 = userConfig.timeout ?? 3000;
console.log(timeout2); // 出力: 0 (期待通り!)

`||` は「Falsyな値(`0`, `””`, `false`, `NaN`, `null`, `undefined`)」すべてを拾ってしまう。
「値が存在しない(`null` / `undefined`)」ことと、「値が空っぽ・虚無である(Falsy)」ことは、セマンティクスとしても別物だということを忘れないでほしい。

—

シニアからのメッセージ

型チェックや値の存在確認は、フロントエンドの堅牢性を支える土台だ。
「動けばいいや」で適当に `null` と `undefined` を混ぜ返していると、将来の自分やチームメンバーがAPI連携や状態管理のバグを踏み抜いたときに泣くことになる。

「これはシステムが勝手に用意したものか?(`undefined`)」
「それとも、人間が意図的に『無い』と決めたものか?(`null`)」

この問いをコードを書くたびに自分に投げかけてみてくれ。それだけで、お前が書くコードの質は一段階、いや二段階確実に跳ね上がるはずだ。さあ、エディタに戻ってコードを磨き上げようか。

コメント

タイトルとURLをコピーしました