0やfalseが初期値に変わる理由|JavaScriptの||と??の使い分け
0を指定したのに3になる、falseにしたのに有効になる。||と??の違いを、空文字列・null・undefined・NaNも含めて確認。初期値の補完と入力チェックを分ける実行例を紹介します。

再試行を無効にしたくて回数に0を指定したのに、初期値の3へ戻ってしまう。そんなときは、値の読み取り方だけでなく、value || 3という補完処理を確認してみてください。
||は0やfalse、空文字列も右辺へ置き換えます。nullとundefinedだけを補いたいなら??を使うと、指定済みの0やfalseを残せます。ただし、??は入力値が正しいかを調べる道具ではありません。
まずは手元で再現する
実行用サンプルを開く・保存するから、default-value-boundaries.mjsという名前で保存して実行してください。
node default-value-boundaries.mjs
確認環境はNode.js v24.14.0です。追加パッケージ、アカウント、ネットワーク通信、ファイルの書き込みは不要です。サンプルは正常例と反例を照合し、最後に「すべての実行例が期待値と一致しました。」と表示します。以下のJavaScriptの枠も、それぞれ別の.mjsファイルで実行できます。
||は「未設定」だけを調べているのではない
右辺を"default"にしたとき、結果は次のように分かれます。
| 左辺の値 | 値 || "default" |
値 ?? "default" |
|---|---|---|
0 |
"default" |
0 |
false |
"default" |
false |
"" |
"default" |
"" |
null |
"default" |
"default" |
undefined |
"default" |
"default" |
NaN |
"default" |
NaN |
"0" |
"0" |
"0" |
||は左辺を真偽として判定し、偽なら右辺を選びます。表の0、false、空文字列などがこの対象です。一方、??は左辺がnullかundefinedのときだけ右辺を選びます。どちらも、選んだ値そのものを返すため、結果が必ず真偽値になるわけではありません。ECMAScriptの評価規則
たとえばfalse ?? trueはfalseです。「通知を無効にする」という明示的な設定を保持できます。逆に、空の表示名を代替表示へ変えたい処理なら、空文字列でも右辺を選ぶことが目的に合う場合があります。
初期値を入れてから、使える値か確認する
再試行回数について、「未指定とnullは3回、0以上の整数なら指定どおり、それ以外はエラー」と決めてみます。これはこの設定項目で採用する方針です。
function retryCount(value) {
const count = value ?? 3;
if (!Number.isInteger(count) || count < 0) {
throw new TypeError('回数は0以上の整数にしてください');
}
return count;
}
console.log(retryCount(0)); // 0
console.log(retryCount(undefined)); // 3
console.log(retryCount(null)); // 3
try {
retryCount('0');
} catch (error) {
console.log(error.name); // TypeError
}
0は残りますが、文字列の"0"は受け付けません。サンプルでは、負の数、小数、NaN、Infinity、空文字列、falseも拒否することを確認しています。
NaN ?? 3の結果はNaNのままです。??に置き換えるだけで不正な計算結果まで直るわけではありません。値を補う条件と、補った後に許可する型・範囲を分けると、どちらの処理を変えるべきかが明確になります。MDNのnull合体演算子の説明
nullに意味があるなら、まとめて補わない
APIや設定によっては、nullが「不明」や「明示的に空」を表すことがあります。その意味を残したいなら、??で初期値に変えるのは適切ではありません。
const preserveNull = (value) => value === undefined ? 3 : value;
console.log(preserveNull(null)); // null
console.log(preserveNull(undefined)); // 3
console.log(Object.hasOwn({ count: undefined }, 'count')); // true
console.log(Object.hasOwn({}, 'count')); // false
前半はundefinedだけを補う例です。後半は「キーは存在するが値がundefined」と「キー自体がない」を分ける例です。どちらも単にobj.count ?? 3とすると同じ3になります。区別が必要な処理では、値だけでなくキーの有無も確認します。
保存前後にこうした区別が失われる問題は、JSONへの保存と読み戻しで変わる値でも扱っています。読み取り後の補完では、保存時に失った情報までは戻せません。
右辺の処理は、必要な場合だけ動く
初期値を作る関数を右辺に置いた場合も、nullかundefinedのときだけ呼ばれます。
let called = 0;
const fallback = () => { called += 1; return 3; };
console.log(0 ?? fallback()); // 0
console.log(called); // 0
console.log(null ?? fallback()); // 3
console.log(called); // 1
||や&&と??を括弧なしで混ぜると、構文エラーになります。たとえばnull || 3 ?? 4は書けません。(null || 3) ?? 4のように、どこを先に判定するかを明示します。これは見た目の推奨ではなく、言語の構文上の規則です。ECMAScriptの構文と評価規則
置き換える前に、残したい値を決める
0やfalseが有効な設定なら、その値を未設定扱いにしないことが出発点です。nullとundefinedを同じ未設定とするなら??、nullを残すなら明示的な条件分岐を使います。
その後で、数値の範囲や文字列の形式を確認します。||をすべて??に置き換えるのではなく、その項目にとって「未設定」と「不正な値」が何かを決めると、初期値が意図せず上書きされる問題を直せます。
確認した一次情報
- ECMAScript 2025: 論理演算とnull合体演算の評価確認日: 2026/09/08
- MDN: null合体演算子確認日: 2026/09/08



