JavaScriptでの開発において、変数の値が未定義の場合にデフォルト値を設定する処理は非常に頻繁に発生します。
以前のJavaScriptでは論理和演算子(||)が代用されてきましたが、意図しない挙動に悩まされる開発者も少なくありませんでした。
そこで登場したのが、ES2020から導入されたNull合体演算子(??)です。
この演算子を正しく理解し使い分けることは、バグの少ない安全なコードを書くための第一歩となります。
本記事では、Null合体演算子の基本的な使い方から論理和演算子との決定的な違い、実戦での活用シーンまでを詳しく紐解いていきます。
Null合体演算子(??)の基本概念
Null合体演算子(??)は、左辺の値がnullまたはundefinedである場合にのみ右辺の値を返します。
それ以外の場合、つまり左辺に何らかの具体的な値が入っている場合は、その左辺の値をそのまま返します。
この挙動を「Nullish(ヌリッシュ)であるかどうか」で判定すると表現することもあります。
まずは、最もシンプルなコード例でその動きを確認してみましょう。
// 左辺がnullの場合
const value1 = null ?? 'デフォルト値';
console.log(value1);
// 左辺がundefinedの場合
const value2 = undefined ?? 'デフォルト値';
console.log(value2);
// 左辺に値がある場合
const value3 = 'JavaScript' ?? 'デフォルト値';
console.log(value3);
"デフォルト値"
"デフォルト値"
"JavaScript"
このように、nullやundefinedといった「値が存在しない」状態を正確に検知してフォールバック処理を行えるのが特徴です。
論理和演算子(||)との決定的な違い
Null合体演算子を理解する上で避けて通れないのが、従来の論理和演算子(||)との比較です。
論理和演算子は、左辺が「偽値(Falsyな値)」である場合に右辺を返します。
JavaScriptにおける偽値には、nullやundefinedだけでなく、数値の0、空文字(””)、論理値のfalse、NaNなどが含まれます。
この仕様の違いが、実務において大きな差を生むことになります。
Falsy(偽値)とNullish(Null値)の比較表
以下の表は、左辺に各値を指定した際に「??」と「||」がどのような結果を返すかをまとめたものです。
| 左辺の値 | 判定(Falsy / Nullish) | 結果:左辺 || ‘Default’ | 結果:左辺 ?? ‘Default’ |
|---|---|---|---|
| null | 両方に該当 | ‘Default’ | ‘Default’ |
| undefined | 両方に該当 | ‘Default’ | ‘Default’ |
| 0 | Falsyのみ | ‘Default’ | 0 |
| “” (空文字) | Falsyのみ | ‘Default’ | “” |
| false | Falsyのみ | ‘Default’ | false |
この表から分かる通り、「0」や「空文字」を有効な値として扱いたい場合、論理和演算子(||)を使用すると意図せずデフォルト値に上書きされてしまいます。
具体的なバグの例:設定値の反映
例えば、ユーザー設定で「通知の表示数」を管理するプログラムを考えてみましょう。
ユーザーが「0」を表示数として設定したい場合、論理和演算子(||)を使うと不具合が発生します。
const userSetting = 0; // ユーザーはあえて「0」を指定した
// 論理和演算子を使用した場合
const countOr = userSetting || 10;
console.log(`||の結果: ${countOr}`);
// Null合体演算子を使用した場合
const countNullish = userSetting ?? 10;
console.log(`??の結果: ${countNullish}`);
"||の結果: 10"
"??の結果: 0"
論理和演算子では、0がFalsyであるためにデフォルト値の10が採用されてしまいました。
一方で、Null合体演算子(??)は0を正常な値として認識し、そのまま0を保持しています。
「値がない(null/undefined)こと」と「値が0であること」を明確に区別できる点が、この演算子の最大のメリットです。
Null合体演算子の正しい使い方と注意点
Null合体演算子は非常に強力ですが、正しく使うためのルールがいくつか存在します。
特に他の論理演算子と併用する場合には、構文上の制約に注意しなければなりません。
他の論理演算子との直接的な併用禁止
JavaScriptの仕様上、?? を && や || と直接並べて書くことは禁止されています。
これは、演算子の優先順位による混乱を避けるための安全策です。
// 構文エラー(SyntaxError)になる例
// const result = a || b ?? c;
// const result = a && b ?? c;
もし併用したい場合は、必ず括弧()を使用して計算の順序を明示する必要があります。
// 括弧を使えばOK
const result = (a || b) ?? c;
このように括弧を用いることで、コードの可読性も向上し、意図した通りの判定ロジックを構築できます。
オプショナルチェイニング(?.)との組み合わせ
Null合体演算子が最も真価を発揮するのは、オプショナルチェイニング(?.)と組み合わせた時です。
オプショナルチェイニングは、深い階層にあるプロパティに安全にアクセスするための仕組みです。
プロパティが存在しない場合に undefined を返すため、その後に ?? を繋げることでスマートにデフォルト値を設定できます。
const userData = {
profile: {
// nicknameは定義されていない
}
};
// profileが存在すればnicknameを取得し、なければ'Guest'を代入する
const displayName = userData.profile?.nickname ?? 'Guest';
console.log(displayName);
"Guest"
この書き方はモダンなJavaScript開発において非常に一般的であり、エラーを防ぎつつ簡潔に記述できる推奨パターンのひとつです。
実務での使い分け:?? と || どちらを選ぶべきか
結局のところ、どちらの演算子を使うべきなのでしょうか。
結論から言えば、現代の開発では「原則として ?? を使い、明確な意図がある時だけ || を使う」というスタンスが安全です。
?? を使うべきケース
基本的には、変数の初期化やデフォルト値の設定において ?? を優先してください。
- APIから取得したデータの欠損(null)を補完したいとき
- 関数の引数が省略された場合のデフォルト処理
- 数値の0や空文字、falseを有効な入力値として受け入れるとき
|| を使うべきケース
逆に、左辺がどんな種類のFalsyな値であっても一律でデフォルト値に飛ばしたい場合にのみ || を使用します。
- 空文字を「名前が入力されていない」とみなして、仮の名前を表示したいとき
- 0という数値を「データが無効」であると解釈させたいとき
「0は有効なデータか?」と自問自答し、答えが「Yes」であれば必ず ?? を選ぶようにしましょう。
まとめ
JavaScriptのNull合体演算子(??)は、nullとundefinedのみを厳格に判定する便利なツールです。
従来の論理和演算子(||)では対応しきれなかった、数値の0や空文字といった「有効なFalsy値」を正しく扱うことができます。
最後に、本記事の重要ポイントを振り返ります。
- ?? は左辺が null または undefined の時だけ右辺を返す。
- || は左辺が Falsy(0, “”, false等)な時にも右辺を返す。
- 数値や文字列を扱う設定値のデフォルト化には
??が適している。 &&や||と併用する際は、必ず括弧()で囲む必要がある。- オプショナルチェイニング
?.と組み合わせることで、より安全なコードが書ける。
これらの特性を理解して使い分けることで、バグの混入を防ぎ、他の開発者にとっても読みやすい堅牢なコードを記述できるようになります。
日々のコーディングにおいて、まずは「??」を使える場面がないか意識することから始めてみてください。
