お疲れ。ちょっと手を止めてこっちを向いてくれ。
君もこれまでのキャリアで、何度となく出会ってきたはずだ。「あれ、なんでこの条件分岐すり抜けたんだ?」という謎のバグに。APIから返ってきたレスポンスをそのまま `if (data.items)` なんて判定してたら、配列が空のときや `0` が返ってきた瞬間に画面が盛大に爆発する。あの冷や汗をかく瞬間、フロントエンドエンジニアなら誰もが一度は経験しているはずだ。
JavaScriptという言語は、良くも悪くも「お節介」な言語だ。私たちが書いた曖昧なコードを、裏側で「こう解釈すればいいんだな?」と勝手に解釈して型を変換してくれる。この「暗黙の型変換(Type Coercion)」の仕様を完全に理解していないと、実務の現場では地雷を踏み続けることになる。
今日は、そんなJavaScriptの挙動の根幹である「Falsyな値の全7選」と、その裏側で何が起きているのかを、シニアの視点から徹底的に叩き込んでやろう。
—
1. そもそも「Falsy」って何だ? ブラウザの裏側で起きていること
JavaScriptの仕様書(ECMAScript)には、すべての値が「真偽値のコンテキスト(`if`文や論理演算子など)」において、`true` として扱われるか、`false` として扱われるかの定義が存在する。
論理的な真偽値である `true` / `false` はもちろんのこと、それ以外のデータ型であっても、条件式に突っ込んだ瞬間に強制的にブール値(Boolean)へと変換される。このとき、「`false` に化ける値たち」のことを、私たちは親愛を込めて Falsy(フォルシー) と呼んでいる。
ちなみに、これら以外の値はすべて Truthy(トルーシー) だ。空の配列 `[]` や空のオブジェクト `{}` すら、JavaScriptの仕様上は バリバリの Truthy なので注意してくれ。「`if ([])` は中身が空だから `false` になるはず」という勘違い、ジュニアの頃にやらかした奴は多いんじゃないか?
—
2. 【完全網羅】Falsyな値の全7選
さあ、いよいよ本丸だ。JavaScriptの世界において、`if` の壁をすり抜けて `false` と判定される値は、以下の 正確に7つ しかない。この顔ぶれを脳裏に焼き付けろ。
1. `false` (言わずもがな、正真正銘のブール値)
2. `0` (数値のゼロ。正のゼロ)
3. `-0` (数値のマイナスゼロ。IEEE 754の呪い)
4. `0n` (BigInt型のゼロ)
5. `””` または `”` または (空文字列)
6. `null` (値が存在しないことを示す意図的なプリミティブ)
7. `undefined` (値がまだ割り当てられていない状態)
8. `NaN` (Not-a-Number。計算不能な数値)
……あれ?数えてみたら8個あるって?
鋭いな。そう、歴史的経緯や仕様の定義で `0` と `-0` は厳密には区別されるが、Falsyの仲間としてはこれらで全部だ。それぞれの「クセ」と実務での注意点を紐解いていこう。
① `false`
これはもう説明不要の王様だ。純粋なブール値。
② `0` と ③ `-0`、そして ④ `0n`
数値を扱うビジネスロジックで最も踏みやすい地雷だ。例えば、ECサイトの数量(quantity)やカートの在庫数を判定するとき。
「在庫が 0 個だから非表示にする」というつもりで `if (item.stock)` と書くと、在庫が1個以上のときは通るが、0個のときに見事にすり抜ける。さらに厄介なのが `-0` だ。JavaScriptは内部的に浮動小数点数を扱っているため、計算結果として `-0` が生まれ、それが条件分岐のバグを引き起こすことがある。
また、最近のモダンな大整数を扱う `0n`(BigInt)も同様にFalsyだ。
⑤ 空文字列 (`””`)
ユーザーの入力フォーム(フォームバリデーション)で頻出する。文字が1文字でも入力されていれば Truthy になるが、完全に空の文字列だと Falsy になる。
ただし、「半角スペースだけの文字列 `” “`」は Truthy なので注意しろ。ここを混同して「入力チェックしたのに空白がすり抜けた!」というバグを量産するジュニアが後を絶たない。
⑥ `null` と ⑦ `undefined`
「何もない」を表す双璧。
- `undefined` は、変数宣言しただけで値を入れていない状態や、存在しないプロパティにアクセスしたときのエラー気味の「未定義」。
- `null` は、開発者が「意図的に値がない」ことを示すために代入する「空っぽ」。
実務では、APIレスポンスの欠損などでこの2つが入り乱れる。これらを安全に弾くために、私たちは `??`(Null合体演算子)や `?.`(オプショナルチェーニング)を使いこなす必要がある。
⑧ `NaN` (Not-a-Number)
「数値ではない何か」を計算しようとした成れの果てだ(例:`Number(“hello”)` や `0 / 0`)。
こいつの最悪な特徴は、「`NaN === NaN` が `false` になる」という狂った仕様を持っていることだ。だから、値が `NaN` かどうかを判定したいときは、絶対に比較演算子を使ってはならない。必ず `Number.isNaN()` を使うのがプロの作法だ。
—
3. 現場で即戦力になるコード例
百聞は一見にしかずだ。実際のフロントエンド開発で、どうやってこれらを安全にハンドリングすべきか、コピペしてすぐにブラウザのコンソールで試せるコードを用意した。エディタに貼って動かしてみてくれ。
/
- 現場でよくある「Falsyの罠」と安全な判定パターン
/
// 1. 数値の判定における罠
const quantity = 0;
// 【悪手】0 のときに条件分岐がスルーされてしまう
if (quantity) {
console.log(‘在庫があります(このログは出ない)’);
} else {
console.log(‘【バグの温床】在庫が0個、または値が存在しません’);
}
// 【正解】厳密に数値の存在や大小を比較する
if (quantity > 0) {
console.log(‘正しく在庫がある場合のみ処理’);
} else {
console.log(‘在庫切れ、または不正な値’);
}
// 2. 文字列の判定と「空白文字」の罠
const userInput = ” “; // ユーザーがうっかりスペースだけ入力した
// 【悪手】空文字ではない(” ” は Truthy)のでスルーされる
if (userInput) {
console.log(‘入力されています(スペースだけど…)’);
}
// 【正解】trim() で余白を削ってから文字数をチェックする
if (userInput && userInput.trim().length > 0) {
console.log(‘有効な文字列が入力されています’);
} else {
console.log(‘実質的に空っぽの入力です!’);
}
// 3. APIレスポンスなどのデフォルト値フォールバック
// null や undefined、あるいは 0 や “” の場合を考慮する
const apiResponseConfig = {
timeout: 0, // 0秒(即時)に設定したい!
retryCount: null
};
// 【悪手】|| 演算子を使うと、0 や “” すら Falsy と判定されてデフォルト値に書き換わってしまう
const badTimeout = apiResponseConfig.timeout || 5000;
console.log(badTimeout); // 5000 になってしまう!(本来の 0 が消された)
// 【正解】Null合体演算子 (??) を使う。こいつは null と undefined のみ陣地を譲る
const safeTimeout = apiResponseConfig.timeout ?? 5000;
console.log(safeTimeout); // 0 (意図した設定値がキープされる!)
—
4. シニアからの実践的アドバイス
いいか、実務においてコードの美しさは「バグの少なさ」と直結している。
「Falsyだから `if (!val)` で一網打尽にできるぜ!」とドヤ顔で書くのは、プログラミング初心者か、仕様の罠にまだボコボコにされていない幸せな奴だけだ。
`0` という有効な数値を扱っているのか、それとも本当にデータが存在しない(`null` / `undefined`)のか。それを意識せずに暗黙の型変換に頼っていると、必ずプロダクション環境でユーザーからのバグ報告踏むことになる。
- 数値を扱うなら `typeof x === ‘number’` や `x > 0` で厳密にみる。
- 文字列なら `.trim()` と組み合わせて空っぽ判定をする。
- デフォルト値を設定するなら `||` ではなく、現代の標準である `??`(Null合体演算子)を使う。
この3つを徹底するだけで、君の書くコードの信頼性は一段も二段も跳ね上がる。
JavaScriptの仕様に怯えるな。仕様を手懐けて、誰よりも堅牢なフロントエンドを構築してやろうぜ。さて、次のタスクに取り掛かろうか。

コメント