nullish 合体演算子 ??
nullish 合体演算子 ?? とは
??でnullやundefinedのときだけデフォルト値を返し、0や空文字を上書きしない安全な書き方を学ぼう。
nullish 合体演算子 ?? でデフォルト値を返す
JavaScript でとても多いパターンが「値があればそれを使い、無ければデフォルト値を使う」というものです。たとえば API のレスポンスでユーザーの表示名がなければ "ゲスト" を出す、設定値がなければ既定値の 10 を使う、というケース。これを安全に書ける専用演算子が ?? (nullish 合体演算子) です。
?? は 2020 年に追加された比較的新しい演算子で、ES2020 から正式に使えるようになりました。書式は value ?? defaultValue で、「value が null または undefined のときに限り defaultValue を返す」という挙動です。
??の合言葉は「nullかundefinedのときだけ右の値」。それ以外の値、たとえば0や""やfalseは そのまま左の値が採用される ところがミソです。
|| との違いを最初に理解する
デフォルト値の指定には、これまで || (論理 OR) もよく使われてきました。しかし || は「左が falsy なら右」を返すので、0 や "" や false のような「正常な値だけど falsy」も上書きしてしまいます。
JavaScript
const countOr = 0 || 10; // 10 になってしまう (0 が falsy)
const countNull = 0 ?? 10; // 0 のまま (0 は null ではない)
const nameOr = "" || "匿名"; // "匿名" ("" が falsy)
const nameNull = "" ?? "匿名"; // "" のまま0 を正常な値として扱いたい (たとえばカウントや座標) ときに || を使うと、意図せず 10 に書き換えられて困ります。?? を使えば、0 や "" はそのまま左の値が残り、本当に null / undefined のときだけデフォルトに置き換わります。
文法と動作
基本の書き方は ?? を真ん中に挟むだけです。
JavaScript
function greet(name) {
const displayName = name ?? "ゲスト";
return `こんにちは、${displayName} さん`;
}
console.log(greet("Naoki")); // "こんにちは、Naoki さん"
console.log(greet(null)); // "こんにちは、ゲスト さん"
console.log(greet(undefined)); // "こんにちは、ゲスト さん"
console.log(greet("")); // "こんにちは、 さん" 空文字は残るname が null や undefined のときだけ "ゲスト" が採用されます。空文字 "" を渡したときは "" がそのまま使われるので、文字列の右側がぎこちなくなりますが、それは値の意味としては「明示的に空文字を渡した」ということになります。
Mermaid で ?? の判定を追う
value ?? "default" の流れを図にすると、たった 1 つの分岐です。
本当にシンプル。|| だと「falsy か?」というもう少し緩い判定になり、?? は「nullish か?」という厳しい判定になる、というのが両者の違いです。
nullish の正体
JavaScript で nullish と呼ばれるのは null と undefined の 2 つだけです。falsy は次の 6 つです。
nullundefined0""(空文字列)falseNaN
?? が反応するのは上の 6 つのうち最初の 2 つだけです。残り 4 つは左の値として尊重されます。この違いを表で覚えておくと、?? と || のどちらを選ぶか迷いません。
JavaScript
console.log(null ?? "X"); // "X"
console.log(undefined ?? "X"); // "X"
console.log(0 ?? "X"); // 0
console.log("" ?? "X"); // ""
console.log(false ?? "X"); // false
console.log(NaN ?? "X"); // NaNよくある間違い
?? の落とし穴を 3 つまとめます。
??と||を混同する —count || 10だとcount = 0を10に書き換えてしまいます。「0や""を正常な値として残したいとき」は必ず??を選ぶこと??と&&||を素のままチェーンする —a || b ?? cのように混ぜると構文エラーになります。(a || b) ?? cかa || (b ?? c)のように 必ずカッコ で結合順を明示してください- 古いブラウザ対応を忘れる —
??は ES2020 機能で、IE11などの古い環境では使えません。Babel などのトランスパイルが必要なケースがあります。最近の Web 開発では実質問題になりません
??は新しいぶん、コードレビューでも「ここは||のままでいいんじゃない?」と聞かれることがあります。「0や空文字を残したいから??」と理由を言えるようになっておきましょう。
代入演算子 ??= も合わせて覚える
おまけで、?? には代入版の ??= もあります。
JavaScript
let name = null;
name ??= "ゲスト";
console.log(name); // "ゲスト"
let count = 0;
count ??= 100;
console.log(count); // 0 のままx ??= y は x = x ?? y と同じ意味です。設定オブジェクトの初期化などで重宝します。
「変数の初期化忘れだけを補いたい」ときに
??=はぴったりです。0の入った変数は上書きしません。
やってみよう
それでは課題に取り組みましょう。withDefault(value, defaultValue) を ?? で書いてください。
書き方の方針は次のとおりです。
return value ?? defaultValue;の 1 行で完成if (value === null)のような条件分岐を書かないこと (??の練習)- テストには
0や""をvalueに渡すケースが含まれます。それらが上書きされないことを確認
?? を使いこなせるようになると、React や TypeScript の世界でも頻出する「安全なデフォルト値」のパターンが自然に書けるようになります。
よくある質問
Q. ブラウザと Node.js で動作は変わりますか?
A. JavaScript の構文・組み込み機能(配列・文字列・Promise 等)はどちらでも同じです。違いは DOM API(ブラウザ専用)と fs などのファイル系(Node 専用)など、実行環境固有の機能です。コアロジックは両方で動くため、テストもしやすくなります。
Q. ES6 以降の新機能は使っても大丈夫ですか?
A. 現代のブラウザ・Node.js は ES2020 以降の機能をほぼサポートしています。古い IE 等を対象にする必要が無ければ、let/const、アロー関数、分割代入、async/await を積極的に使ってください。トランスパイル(Babel/Vite)が必要なケースは年々減っています。
Q. TypeScript に進む価値はありますか?
A. 型情報があるとリファクタやエディタ補完が劇的に効くため、規模が大きくなるなら TypeScript への移行を強くおすすめします。最初は any を許容しつつ徐々に型を付ければ、JS の知識をそのまま活かせます。
次のレッスン
次は オプショナルチェーン ?. で、?? で null や undefined のときだけデフォルト値を返し、0 や空文字を上書きしない安全な書き方を学ぼう を学びます。
事前確認 — 進む前に次の 3 つができることを確認しましょう。
- ?? 演算子 の要点を自分の言葉で説明できる
- このレッスンの最小コード (または操作手順) を見ずに書ける
- 練習問題やクイズで間違えた箇所を読み直して理解した
理解度チェック (30 秒)
Q. ?? 演算子 とは何か、1 文で説明してください。
A. 本文の「このレッスンで分かること」または冒頭の説明文を見直し、自分の言葉で要約できれば OK。詰まったら本レッスンの最初の H2 セクションを読み返してみましょう。
関連レッスン
要件
- 関数名は
withDefault、引数はvalueとdefaultValueの 2 つにすること - 判定には
??(nullish 合体演算子) を使うこと ||やif文で代用しないこと
入出力例
test-cases.txt
withDefault(null, "ゲスト") → "ゲスト"
withDefault(null, 10) → 10
withDefault(0, 10) → 0
withDefault("", "X") → ""
withDefault(false, true) → false
withDefault("Naoki", "ゲスト") → "Naoki"