「何もない」を表す2つの値
多くの言語では「値がない」を表すものは1つだけですが、JavaScriptには null と undefined という2つがあります。両者は紛らわしいほど似た振る舞いをする一方で、微妙に違うせいでベテラン開発者でもつまずくことがあります。この違いをきちんと押さえておくのは、10分の投資に見合う価値があります。
ざっくり言うと、こうです。
undefinedは、何かが欠けているときにJavaScriptが勝手に割り当てる値。nullは、「意図的に空にしておく」と自分で明示的に書く値。
パターンに気づきましたか?上で出てきた undefined は、どれも JavaScript が値を見つけられなかったケースです。一方 null は、誰かが明示的に書いたから存在するんです。
undefined が現れる場面
undefined が登場するシチュエーションはいくつか決まっていて、どれも「値が用意されていない」バリエーションです。
いずれのケースでも、JavaScript は値を取りに行ったものの、そこに何もなかったというだけの話です。undefined は「探したけど値がなかったよ」というエンジンからのサインだと思ってください。
もちろん自分で undefined を代入することもできます(let x = undefined; のように)。ただし、やらないほうが無難です。undefined は「JavaScript が何も見つけられなかった」というシグナルとして残しておき、自分の意思で「値がない」ことを示したいときは null を使いましょう。これが null と undefined の使い分けの基本です。
null はどこから来るのか
null は、誰かが明示的に書いたときにしか現れません。つまり、そこがポイントで、意図的に「値がない」ことを示すための目印なのです。
DOMのAPIではnullがよく使われます。例えばdocument.getElementById("missing")の戻り値はundefinedではなくnullです。これはブラウザが「探したけど、該当する要素はなかったよ」と明示的に伝えているからです。JSON.parse("null")も同様にnullを返します。そもそもJSONにはundefinedという概念がないんですね。
イメージとしてはこうです。undefinedは「デフォルトの不在」、nullは「意図的な不在」。
typeof の落とし穴
有名なやつです。
typeof null が "object" を返すのは、実は1995年から残っているバグなんです。修正してしまうと既存のサイトが軒並み壊れてしまうため、そのまま放置され続けています。とはいえ null はオブジェクトでは ありません 。undefined や数値、文字列、真偽値と同じくプリミティブ値です。typeof の結果が嘘をついているだけ、というわけですね。
実用面での影響としては、null の判定に typeof はまったく使えません。素直に比較演算子で調べましょう。
もっと多い使い方としては、両方をまとめて判定するパターン——次のセクションで見ていきましょう。
== null で両方まとめて判定する
実際のコードでは、値が null なのか undefined なのかを区別する必要はほとんどありません。使う前に「値が入っていないかどうか」を確認したいだけ、というケースが大半です。そんなときの定番は、null との緩い等価比較(==)です。
value == null は、値が null または undefined のときだけ true になり、それ以外(0、""、false など)はすべて false になります。たいていの場面ではこの挙動こそが欲しいものです。=== ではなく == を使うのが推奨される、数少ないケースのひとつですね。リンターもこれを理解していて、ちゃんと許容してくれます。
もっと明示的に書きたいなら、value === null || value === undefined と書けば同じ意味になりますし、読み手にも意図が伝わりやすいです。
Nullish 演算子:?? と ?.
null と undefined を扱いやすくするために、専用の演算子が2つ追加されました。どちらもこの2つの値を同じものとして扱い、それ以外の値はそのまま素通りさせます。
Nullish 合体演算子(??) は、左辺が null または undefined のときだけフォールバック値を返します。
|| と比較してみてください。|| なら 0 は falsy なので 3 に置き換わってしまいます。?? はもっと厳格で、null・undefined の2つだけに反応します。
オプショナルチェーン(?.) は、チェーンの途中で null や undefined に遭遇すると、そこで評価を打ち切って undefined を返します。
どちらの演算子も「この値は nullish なのか?」という頻出のチェックをラクに書くために用意されています。詳しい使い方はカリキュラムの後半でじっくり扱います。
デフォルト引数が効くのは undefined のときだけ
地味ですが重要なルールがあります。関数のデフォルト引数が適用されるのは undefined が渡されたときだけで、null には発動しません。
null を渡すと「値を設定しないことを明示的に選んだ」と見なされ、そのまま尊重されます。null の場合もデフォルト値にフォールバックさせたいなら、関数内で ?? を使いましょう。
この違いは本当に多くの人がハマるポイントです。デフォルト値は「引数が渡されていない」ケースを埋めるもので、?? は「nullish な値」を埋めるもの。役割が違います。
JSON に undefined が存在しない問題
JSON には null はありますが、undefined はありません。そのため、シリアライズするときに気づかないうちにハマることがあります。
age フィールドがまるごと消えてしまいました。JSON.stringify は値が undefined のプロパティを捨ててしまうからです。一方、null は JSON が正式にサポートしているので残ります。オブジェクトを JSON に通して戻すと、undefined のプロパティが気づかないうちに消えてしまう——これはよくある落とし穴です。
配列の場合、undefined は null に変換されます:
APIのペイロードを設計するときは、「値なし」を表すフィールドには undefined ではなく null を使うのがおすすめです。こちらなら通信を経ても消えずに残ります。
null と undefined の使い分け
自分のコードで採用するなら、こんなルールが現実的です。
undefinedは「そもそも与えられていない」を表す — 引数が渡されていない、変数が未代入、プロパティが存在しない、といったケース。自分でundefinedを明示的に代入するのは避けます。nullは「意図的に空であることをはっきり示したい」ときに使う — ログアウト状態のユーザー、未選択のオプション、クリアされたフォーム欄など。- API の境界では両方を受け入れる(
== nullや??を使う)。ただし、自分が 返す 側は必ずどちらか一方に統一しましょう。
スタイルガイドによっては(TypeScript のガイドラインなど)null を一切使わず undefined だけで通すものもあります。これも一理あって、値が 2 種類より 1 種類の方がシンプルです。プロジェクトごとに方針を決めて、全体で揃えるのが大事です。
次回:型変換(Type Coercion)
null と undefined は、JavaScript が数値・文字列・真偽値に変換するときにそれぞれ独特の挙動を見せます。たとえば Number(null) は 0 なのに、Number(undefined) は NaN。こうした非対称さが、実際のバグの原因になったりします。次は型変換(Type Coercion)の話です。ルール全体が見えてくると、JavaScript の「クセ」と思っていた挙動の多くが、意外とスッキリ腑に落ちるはずです。
よくある質問
JavaScriptのnullとundefinedは何が違うの?
undefined は「まだ値が入っていない」状態を表します。宣言だけした変数、渡されなかった引数、存在しないオブジェクトのプロパティなど、JavaScriptが自動的に返してくるのがこれです。一方 null は「値が無いことを明示的に示す」もので、自分で意図的に代入するもの。JavaScriptが勝手に null を返してくることはなく、必ず人間が書いた場合だけ登場します。
nullとundefinedを一度にチェックするには?
value == null と書けばOKです。ゆるい等価比較(==)では、null と undefined はお互いだけが等しいと判定されるので、x == null は null か undefined のときだけ true になります。基本は === 推奨のJavaScriptですが、この書き方だけは例外的に慣用表現として定着しています。
なぜ typeof null は 'object' になるの?
これは初期のJavaScriptから残っている有名なバグで、直すと既存のWebが壊れてしまうため放置されています。null はプリミティブなのに typeof null は 'object' を返します。null だけをピンポイントで判定したいときは、素直に value === null と比較するのが確実です。
自分のコードではnullとundefinedどっちを使うべき?
基本方針は、undefined は「何も渡されていない」、null は「意図的に空であることを示す」と役割を分けること。ただし最近はTypeScriptのスタイルガイドを含め、null を使わず undefined に統一する派も多いです。大事なのはプロジェクト内で方針を一つに決めて、それを貫くことです。