JavaScriptで「値がなければデフォルト値を使う」ような書き方をするとき、??(Null合体演算子)、||(論理和)、? :(三項演算子)のどれを使うかで迷うことがあります。どれも似た結果になることが多いのですが、0 や空文字の扱いが違うため、選び方を間違えると「0を設定したのにデフォルト値になる」といった不具合になります。
この記事では、3つの違いと使い分けを、実際に動くコードで確かめます。
3つの演算子の違い
a ?? b:aがnullかundefinedのときだけbになる。それ以外はaのままa || b:aが Falsy(後で説明)ならbになる。0や空文字もbに置き換わる条件 ? x : y:条件が成り立つならx、成り立たなければyになる。条件は自由に書ける
?? と || は「デフォルト値を入れる」ための演算子、三項演算子は「条件で値を切り替える」ための演算子と考えると整理しやすくなります。?? はES2020で追加された、比較的新しい演算子です。
Falsy(偽とみなされる値)とは
JavaScriptでは、if文や || などで「偽」として扱われる値を Falsy と呼びます。主な Falsy な値は次のとおりです。
| 値 | 意味 |
|---|---|
false | 真偽値の偽 |
0、-0 | 数値の0 |
0n | BigInt(大きな整数の型)の0 |
"" | 空文字 |
null | 「値がない」を表す値 |
undefined | 「まだ値が入っていない」を表す値 |
NaN | 数値ではないことを表す値 |
?? が反応するのは、このうち null と undefined の2つだけです。C言語でも 0 は偽として扱われますが、JavaScriptでは空文字や NaN も偽になるのが違うところです。
0を設定したのにデフォルト値になる例
「表示する件数」をユーザーが設定できて、設定がなければ10件にする場合を考えます。ユーザーが、わざと 0 を設定したとします。
const userCount = 0; // ユーザーがわざと 0 を設定した
console.log(userCount ?? 10); // 0 (0 は null でも undefined でもないので、そのまま)
console.log(userCount || 10); // 10(0 は Falsy なので、10 に置き換わる)
console.log(userCount ? userCount : 10); // 10(|| と同じ結果)|| や「userCount ? userCount : 10」の書き方だと、意図して設定した 0 が 10 に置き換わってしまいます。?? なら、未設定(null や undefined)のときだけ 10 になり、0 はそのまま残ります。
いろいろな値で比べると、次のようになります(コメントの結果は、見やすいように整えています。コンソールでは空文字が何も表示されないなど、見た目が少し違います)。
const values = [null, undefined, 0, '', false, NaN, 5, 'abc'];
for (const v of values) {
console.log(v, '→ ??:', v ?? 'デフォルト', '/ ||:', v || 'デフォルト');
}
// null → ??: デフォルト / ||: デフォルト
// undefined → ??: デフォルト / ||: デフォルト
// 0 → ??: 0 / ||: デフォルト
// '' → ??: '' / ||: デフォルト
// false → ??: false / ||: デフォルト
// NaN → ??: NaN / ||: デフォルト
// 5 → ??: 5 / ||: 5
// 'abc' → ??: 'abc' / ||: 'abc'結果が分かれるのは、0、空文字、false、NaN のときです。これらを「正しい値」として受け付けたいなら ??、「値がないのと同じ」として扱いたいなら || を使います。たとえば、入力欄が空なら「名無し」と表示したいときは、空文字も置き換えたいので || が合っています。
三項演算子で書くとどうなる?
?? と同じ動きは、三項演算子でも書けます。?? がなかったころは、このように書いていました。
const userCount = 0;
// ?? と同じ動きを三項演算子で書いた形
const count1 = userCount !== null && userCount !== undefined ? userCount : 10;
// ?? を使うと、これだけで済む
const count2 = userCount ?? 10;
console.log(count1, count2); // 0 0結果は同じですが、?? のほうが短く、「値がなければ 10」という意図が読み取りやすくなります。デフォルト値を入れるだけなら、?? を使うのがおすすめです。
三項演算子が向いている場面
三項演算子は、null かどうかに限らず、どんな条件でも書けます。数値の大きさや文字列の中身で値を切り替えるときは、三項演算子を使います。
const score = 85;
const result = score >= 80 ? '合格' : '不合格';
console.log(result); // 合格ただし、三項演算子を何重にも重ねると読みにくくなります。条件が3つ以上になるときは、if文で書いたほうが分かりやすいことが多いです。
// 重ねすぎた例(読みにくい)
const grade = score >= 90 ? 'A' : score >= 80 ? 'B' : score >= 70 ? 'C' : 'D';?? と一緒によく使う書き方
?.(オプショナルチェーン)と組み合わせる
オブジェクトの奥の値を読むとき、途中が null や undefined だとエラーになります。?. を使うと、途中に値がなければエラーにせず undefined を返すので、?? と組み合わせてデフォルト値を入れられます。
const settings = {}; // display の設定がまだない
// settings.display.count と書くと、display が undefined なのでエラーになる
const count = settings.display?.count ?? 10;
console.log(count); // 10??=(Null合体代入)
「変数が null か undefined のときだけ、値を入れる」ときは ??= も使えます(ES2021で追加)。
const options = { count: 0 };
options.count ??= 10; // 0 なので変わらない
options.title ??= '一覧'; // まだないので '一覧' が入る
console.log(options); // { count: 0, title: '一覧' }注意:|| や && と混ぜるときはカッコが必要
?? を || や && とカッコなしで並べると、文法エラーになります。どちらを先に計算するか、カッコではっきり書く必要があります。
const a = null;
const b = 0;
// const x = a || b ?? 10; // SyntaxError(カッコがないとエラー)
const x = (a || b) ?? 10; // OK
console.log(x); // 0どれを使うかの目安
- 値がないときだけデフォルト値にしたい(
0や空文字も正しい値として残したい)→?? - 空文字や
0も「値がない」として扱いたい →|| - 大きさや中身など、条件で値を切り替えたい → 三項演算子(条件が多いときは if文)
迷ったときは、「0 や空文字が来たらどうしたいか」を考えると決めやすくなります。
まとめ
??はnullとundefinedのときだけ右側の値になる。0や空文字はそのまま残る||は Falsy な値をすべて右側の値に置き換える- 三項演算子は、どんな条件でも値を切り替えられる
?.や??=と組み合わせると便利。||や&&と混ぜるときはカッコを付ける
この記事のコードは、ブラウザのコンソールやCodePenに貼ればすぐに試せます。あわせて、「文字列の ‘ と ” と ` の違い」や「filterメソッドの書き方」も参考にしてみてください。



コメント