JavaScript でオブジェクトの深い階層のプロパティにアクセスすると、「途中の値が undefined で読めずにエラーになる」という場面によく出会います。これをすっきり書けるのが、オプショナルチェーン演算子 ?. と、Null合体演算子 ?? です。この記事では、2つの演算子の使い方と、組み合わせて安全に値を取り出す方法、似ている || との違いまで解説します。
目次
なぜ必要か:深い階層へのアクセスでエラーになる
たとえば API から受け取ったデータで、ユーザーの住所の郵便番号を取り出したいとします。次のように書くと、user.address が存在しないときに TypeError が発生してスクリプトが止まってしまいます。
const user = { name: "佐藤" }; // address は無い
// address が undefined なので、その先の zip を読もうとしてエラー
const zip = user.address.zip;
// → TypeError: Cannot read properties of undefined (reading 'zip')
これを防ぐために、以前は user.address && user.address.zip のように && をいくつもつなげて「存在するか確認しながら進む」書き方をしていました。階層が深くなるほど冗長になり、読みにくくなるのが悩みでした。
オプショナルチェーン(?.)の基本
オプショナルチェーン ?. は、. の手前の値が null または undefined のとき、その先を読まずに undefined を返してくれる演算子です。エラーを出さずに「無ければ undefined」で済ませられます。
const user = { name: "佐藤" };
// address が無ければ、その時点で undefined を返す(エラーにならない)
const zip = user.address?.zip;
console.log(zip); // undefined
// address がある場合は、ちゃんと値が取れる
const user2 = { name: "鈴木", address: { zip: "100-0001" } };
console.log(user2.address?.zip); // "100-0001"
配列や関数呼び出しにも使える
?. はプロパティだけでなく、配列の要素アクセスや関数呼び出しの前にも置けます。それぞれ ?.[ と ?.( という形になります。
const data = { items: [{ id: 1 }] };
// 配列要素へのアクセス: items が無くてもエラーにならない
console.log(data.items?.[0]?.id); // 1
console.log(data.tags?.[0]); // undefined
// 関数呼び出し: コールバックが渡されていれば実行する
function run(callback) {
// callback が undefined なら呼び出さない(エラーにならない)
callback?.();
}
run(); // 何も起きない
run(() => console.log("実行")); // "実行"
Null合体演算子(??)の基本
?? は「左側が null または undefined なら、右側の値を使う」という演算子です。値が無いときの初期値(デフォルト値)を指定するのにぴったりです。
const name = null;
console.log(name ?? "ゲスト"); // "ゲスト"(null なので右側)
const count = 0;
console.log(count ?? 10); // 0(0 は null/undefined ではないのでそのまま)
?. と ?? を組み合わせる
この2つは一緒に使うと真価を発揮します。?. で安全に値を取り出し、取れなかった(undefined だった)ときは ?? でデフォルト値に置き換える、という流れです。冒頭の郵便番号の例も、たった1行で安全に書けます。
const user = { name: "佐藤" };
// address が無ければ undefined → ?? で "未登録" に置き換え
const zip = user.address?.zip ?? "未登録";
console.log(zip); // "未登録"
?? と || の違い
デフォルト値の指定には昔から || が使われてきましたが、?? とは判定基準が異なります。|| は左側が「falsy(偽とみなされる値)」なら右側を使うのに対し、?? は「null または undefined」のときだけ右側を使います。
falsy には 0 や空文字 ""、false も含まれます。そのため 0 や空文字を「正しい値」として扱いたい場面では、|| だと意図せず右側に置き換わってしまいます。
const count = 0;
// || は 0 を falsy とみなすため、右側に置き換わってしまう
console.log(count || 10); // 10(意図しない結果)
// ?? は 0 をそのまま採用する
console.log(count ?? 10); // 0(意図通り)
2つの違いを整理すると次のようになります。「0 や空文字を有効な値として残したい」ときは ?? を選びましょう。
| 左側の値 | || "右" の結果 | ?? "右" の結果 |
|---|---|---|
null / undefined | “右” | “右” |
0 | “右” | 0 |
""(空文字) | “右” | "" |
false | “右” | false |
使うときに気をつけたいこと
?? と || / && は括弧なしで混在できない
?? を || や && と同じ式の中でそのまま並べると、優先順位が紛らわしいため構文エラーになります。混ぜて使うときは括弧で意図を明示してください。
// NG: SyntaxError になる
// const v = a || b ?? c;
// OK: 括弧でグループ化する
const v = (a || b) ?? c;
エラーを隠しすぎない
?. は便利ですが、本来あるはずのデータが無いケースまで undefined で握りつぶすと、バグの発見が遅れます。「無いこともあり得る」と分かっている箇所にだけ使い、必ず存在するはずの値には通常の . を使うのがおすすめです。
まとめ
オプショナルチェーン ?. と Null合体演算子 ?? は、値が無いかもしれないデータを安全に扱うための演算子です。
?.は手前がnull/undefinedならエラーを出さずundefinedを返す??は左側がnull/undefinedのときだけ右側のデフォルト値を使うobj?.prop ?? デフォルトの形で「安全に取得して、無ければ初期値」が1行で書ける0や空文字を残したいときは||ではなく??を使う
API レスポンスやフォーム入力など、値の有無が不確実なデータを扱うときにとても役立ちます。詳しい仕様は MDN のオプショナルチェーン も参考にしてください。