真偽値と条件の落とし穴 — JavaScript Tips
真偽値と条件の落とし穴 — JavaScript Tips
if や && / || は、値を真偽に変換してから分岐します。falsy になるのは false / 0 / "" / null / undefined / NaN など少数です。|| と ??、?. の差を知っておくと、フォームや設定で 0 や空文字を消してしまう事故を避けやすくなります。
参考: Truthy · Falsy · Nullish coalescing operator (??) · Optional chaining (?.) · 論理演算子
目次
Truthy と Falsy とは
条件式では、値は自動的に真偽値に変換されます。
Falsy(偽とみなされる 8 つ)
| 値 | 補足 |
|---|---|
false |
論理偽 |
0 |
数値のゼロ |
-0 |
同上 |
0n |
BigInt のゼロ |
"" |
空文字列 |
null |
意図的な「値なし」 |
undefined |
未定義 |
NaN |
非数 |
これ以外はほぼ Truthy です。例えば [](空配列)、{}(空オブジェクト)、"0"(文字列のゼロ)はすべて truthy です。
if ([]) { console.log("空配列は truthy"); // 実行される}if ("") { // 実行されない} else { console.log("空文字は falsy");}「値があるかどうか」を判定するとき、空配列や空オブジェクトを「データなし」と誤認 しないよう注意が必要です。
if と Boolean 変換
明示的に真偽値へ変換するには Boolean() や二重否定 !! を使います。
const input = " ";console.log(Boolean(input)); // true(空白だけの文字列は truthy)console.log(!!input); // trueconst count = 0;if (count) { // 実行されない — 0 は falsy}// 数値 0 を有効な値として扱うならif (count !== undefined && count !== null) { console.log("count は 0 かもしれないが、設定はされている");}「ユーザーが入力したか」を空文字で判定する例です。
function isFilled(value) { return value !== "" && value !== null && value !== undefined;}isFilled(0); // trueisFilled(""); // falseisFilled(null); // falseデフォルト値と論理演算子
||(論理 OR)
左辺が falsy なら右辺を返します。
const name1 = "" || "ゲスト";console.log(name1); // "ゲスト"const port1 = 0 || 3000;console.log(port1); // 3000 — 0 も falsy なので置き換わる??(Nullish coalescing)
左辺が null または undefined のときだけ 右辺を返します。
const name2 = "" ?? "ゲスト";console.log(name2); // "" — 空文字は残るconst port2 = 0 ?? 3000;console.log(port2); // 0 — 0 は有効な値として残るconst missing = null ?? "デフォルト";console.log(missing); // "デフォルト"デフォルト値の設定 では、0 や "" を正当な値として扱うかどうかで || と ?? を選び分けます。
&&(論理 AND)
左辺が falsy なら左辺を、そうでなければ右辺を返します(短絡評価)。
const user = { name: "田中" };const greeting = user && user.name && `こんにちは、${user.name}`;console.log(greeting); // "こんにちは、田中"const empty = null;console.log(empty && empty.name); // null(エラーにならない)&& は「左が存在するときだけ右を評価する」ガードにも使えます。ネストが深くなるなら ?. の方が追跡しやすいです。
安全なプロパティアクセス
Optional chaining ?. は、参照先が null または undefined のとき エラーにせず undefined を返します。
const response = { user: { profile: { city: "東京", }, },};console.log(response.user?.profile?.city); // "東京"console.log(response.admin?.profile?.city); // undefined(admin がない・TypeError にならない)// メソッド呼び出しconst obj = { greet() { return "hi"; } };console.log(obj.greet?.()); // "hi"console.log(obj.missing?.()); // undefined// 配列の要素const arr = [1, 2, 3];console.log(arr?.[10]); // undefined?. は 参照の連鎖が途切れた時点で止まる ので、深いネストの API レスポンスを扱うときに便利です。
?. と ?? を続ける書き方も定番です。
const city = response.user?.profile?.city ?? "未設定";console.log(city);短絡評価の実用パターン
デフォルト値
// 環境変数風のオブジェクトconst config = { timeout: 0 };const timeout = config.timeout ?? 5000;const retries = config.retries ?? 3;条件付き実行
const isDev = true;isDev && console.log("デバッグモード");// 関数があるときだけ呼ぶconst onSuccess = null;onSuccess?.();値の選択(|| の古典パターン)
function displayName(user) { return user.nickname || user.name || "匿名";}ニックネームが空文字 "" のときも本名にフォールバックしたいなら || が意図に合います。0 を残したいフィールドでは ?? を使います。
三項演算子との使い分け
const status = isActive ? "有効" : "無効";// 複雑な条件は if のほうが読みやすいことが多いlet label;if (score >= 90) { label = "A";} else if (score >= 70) { label = "B";} else { label = "C";}比較と真偽値の混同
== と ===
== は型変換を伴う比較です。意図しない truthy/falsy との混同を避けるため、通常は === を使う のが無難です。
console.log(0 == false); // trueconsole.log(0 === false); // falseconsole.log("" == false); // true真偽値との比較
const flag = true;if (flag === true) { /* OK */ }if (flag) { /* これで十分なことが多い */ }// NG になりがちif (flag == true) { /* 動くが冗長 */ }Boolean オブジェクト
new Boolean(false) はオブジェクトなので truthy です。プリミティブの false と混同しないでください。
const boxed = new Boolean(false);if (boxed) { console.log("オブジェクトは truthy"); // 実行される}よくある失敗
空配列を「データなし」と判定していない
const items = [];if (items) { console.log("一覧を描画"); // 空なのに描画処理に入る}// 件数で判定するif (items.length > 0) { console.log("一覧を描画");}?? と || を混ぜてパースエラーになる
?? と || / && を 括弧なしで混在 させると構文エラーになります。
// NG// const x = a || b ?? c;// OKconst x = (a || b) ?? c;const y = a || (b ?? c);?. の戻り値が undefined なのにメソッドを呼んでいる
const data = null;// NG: ?. の結果にさらに通常の . でアクセス// data?.user.name; // user が undefined なら .name でエラー// OKdata?.user?.name;?. は その演算の直前 だけを短絡します。チェーン全体に ?. を付けましょう。
0 や "" を消してしまう
const quantity = 0;const display = quantity || "未入力"; // "未入力" になってしまうconst fixed = quantity ?? "未入力"; // 0 のままフォームの数値や金額では ?? を優先的に検討します。
&& で代入しようとして値がおかしい
let value;value = someCondition && "設定値";// someCondition が false なら value は false(文字列ではない)意図が「条件付きで文字列を入れる」なら三項演算子のほうが明確です。
value = someCondition ? "設定値" : undefined;if や && / || は、値を真偽に変換してから分岐します。falsy になるのは false / 0 / "" / null / undefined / NaN など少数です。|| と ??、?. の差を知っておくと、フォームや設定で 0 や空文字を消してしまう事故を避けやすくなります。
参考: Truthy · Falsy · Nullish coalescing operator (??) · Optional chaining (?.) · 論理演算子
目次
Truthy と Falsy とは
条件式では、値は自動的に真偽値に変換されます。
Falsy(偽とみなされる 8 つ)
| 値 | 補足 |
|---|---|
false |
論理偽 |
0 |
数値のゼロ |
-0 |
同上 |
0n |
BigInt のゼロ |
"" |
空文字列 |
null |
意図的な「値なし」 |
undefined |
未定義 |
NaN |
非数 |
これ以外はほぼ Truthy です。例えば [](空配列)、{}(空オブジェクト)、"0"(文字列のゼロ)はすべて truthy です。
if ([]) { console.log("空配列は truthy"); // 実行される}if ("") { // 実行されない} else { console.log("空文字は falsy");}「値があるかどうか」を判定するとき、空配列や空オブジェクトを「データなし」と誤認 しないよう注意が必要です。
if と Boolean 変換
明示的に真偽値へ変換するには Boolean() や二重否定 !! を使います。
const input = " ";console.log(Boolean(input)); // true(空白だけの文字列は truthy)console.log(!!input); // trueconst count = 0;if (count) { // 実行されない — 0 は falsy}// 数値 0 を有効な値として扱うならif (count !== undefined && count !== null) { console.log("count は 0 かもしれないが、設定はされている");}「ユーザーが入力したか」を空文字で判定する例です。
function isFilled(value) { return value !== "" && value !== null && value !== undefined;}isFilled(0); // trueisFilled(""); // falseisFilled(null); // falseデフォルト値と論理演算子
||(論理 OR)
左辺が falsy なら右辺を返します。
const name1 = "" || "ゲスト";console.log(name1); // "ゲスト"const port1 = 0 || 3000;console.log(port1); // 3000 — 0 も falsy なので置き換わる??(Nullish coalescing)
左辺が null または undefined のときだけ 右辺を返します。
const name2 = "" ?? "ゲスト";console.log(name2); // "" — 空文字は残るconst port2 = 0 ?? 3000;console.log(port2); // 0 — 0 は有効な値として残るconst missing = null ?? "デフォルト";console.log(missing); // "デフォルト"デフォルト値の設定 では、0 や "" を正当な値として扱うかどうかで || と ?? を選び分けます。
&&(論理 AND)
左辺が falsy なら左辺を、そうでなければ右辺を返します(短絡評価)。
const user = { name: "田中" };const greeting = user && user.name && `こんにちは、${user.name}`;console.log(greeting); // "こんにちは、田中"const empty = null;console.log(empty && empty.name); // null(エラーにならない)&& は「左が存在するときだけ右を評価する」ガードにも使えます。ネストが深くなるなら ?. の方が追跡しやすいです。
安全なプロパティアクセス
Optional chaining ?. は、参照先が null または undefined のとき エラーにせず undefined を返します。
const response = { user: { profile: { city: "東京", }, },};console.log(response.user?.profile?.city); // "東京"console.log(response.admin?.profile?.city); // undefined(admin がない・TypeError にならない)// メソッド呼び出しconst obj = { greet() { return "hi"; } };console.log(obj.greet?.()); // "hi"console.log(obj.missing?.()); // undefined// 配列の要素const arr = [1, 2, 3];console.log(arr?.[10]); // undefined?. は 参照の連鎖が途切れた時点で止まる ので、深いネストの API レスポンスを扱うときに便利です。
?. と ?? を続ける書き方も定番です。
const city = response.user?.profile?.city ?? "未設定";console.log(city);短絡評価の実用パターン
デフォルト値
// 環境変数風のオブジェクトconst config = { timeout: 0 };const timeout = config.timeout ?? 5000;const retries = config.retries ?? 3;条件付き実行
const isDev = true;isDev && console.log("デバッグモード");// 関数があるときだけ呼ぶconst onSuccess = null;onSuccess?.();値の選択(|| の古典パターン)
function displayName(user) { return user.nickname || user.name || "匿名";}ニックネームが空文字 "" のときも本名にフォールバックしたいなら || が意図に合います。0 を残したいフィールドでは ?? を使います。
三項演算子との使い分け
const status = isActive ? "有効" : "無効";// 複雑な条件は if のほうが読みやすいことが多いlet label;if (score >= 90) { label = "A";} else if (score >= 70) { label = "B";} else { label = "C";}比較と真偽値の混同
== と ===
== は型変換を伴う比較です。意図しない truthy/falsy との混同を避けるため、通常は === を使う のが無難です。
console.log(0 == false); // trueconsole.log(0 === false); // falseconsole.log("" == false); // true真偽値との比較
const flag = true;if (flag === true) { /* OK */ }if (flag) { /* これで十分なことが多い */ }// NG になりがちif (flag == true) { /* 動くが冗長 */ }Boolean オブジェクト
new Boolean(false) はオブジェクトなので truthy です。プリミティブの false と混同しないでください。
const boxed = new Boolean(false);if (boxed) { console.log("オブジェクトは truthy"); // 実行される}よくある失敗
空配列を「データなし」と判定していない
const items = [];if (items) { console.log("一覧を描画"); // 空なのに描画処理に入る}// 件数で判定するif (items.length > 0) { console.log("一覧を描画");}?? と || を混ぜてパースエラーになる
?? と || / && を 括弧なしで混在 させると構文エラーになります。
// NG// const x = a || b ?? c;// OKconst x = (a || b) ?? c;const y = a || (b ?? c);?. の戻り値が undefined なのにメソッドを呼んでいる
const data = null;// NG: ?. の結果にさらに通常の . でアクセス// data?.user.name; // user が undefined なら .name でエラー// OKdata?.user?.name;?. は その演算の直前 だけを短絡します。チェーン全体に ?. を付けましょう。
0 や "" を消してしまう
const quantity = 0;const display = quantity || "未入力"; // "未入力" になってしまうconst fixed = quantity ?? "未入力"; // 0 のままフォームの数値や金額では ?? を優先的に検討します。
&& で代入しようとして値がおかしい
let value;value = someCondition && "設定値";// someCondition が false なら value は false(文字列ではない)意図が「条件付きで文字列を入れる」なら三項演算子のほうが明確です。
value = someCondition ? "設定値" : undefined;