1. ホーム
  2. JavaScript

【JavaScript】オプショナルチェーン(?.)とNull合体演算子(??)の使い方

Share

JavaScript でオブジェクトの深い階層のプロパティにアクセスすると、「途中の値が undefined で読めずにエラーになる」という場面によく出会います。これをすっきり書けるのが、オプショナルチェーン演算子 ?. と、Null合体演算子 ?? です。この記事では、2つの演算子の使い方と、組み合わせて安全に値を取り出す方法、似ている || との違いまで解説します。

なぜ必要か:深い階層へのアクセスでエラーになる

たとえば API から受け取ったデータで、ユーザーの住所の郵便番号を取り出したいとします。次のように書くと、user.address が存在しないときに TypeError が発生してスクリプトが止まってしまいます。

script.js
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」で済ませられます。

script.js
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"

配列や関数呼び出しにも使える

?. はプロパティだけでなく、配列の要素アクセスや関数呼び出しの前にも置けます。それぞれ ?.[?.( という形になります。

script.js
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 なら、右側の値を使う」という演算子です。値が無いときの初期値(デフォルト値)を指定するのにぴったりです。

script.js
const name = null;
console.log(name ?? "ゲスト"); // "ゲスト"(null なので右側)

const count = 0;
console.log(count ?? 10); // 0(0 は null/undefined ではないのでそのまま)

?. と ?? を組み合わせる

この2つは一緒に使うと真価を発揮します。?. で安全に値を取り出し、取れなかった(undefined だった)ときは ?? でデフォルト値に置き換える、という流れです。冒頭の郵便番号の例も、たった1行で安全に書けます。

script.js
const user = { name: "佐藤" };

// address が無ければ undefined → ?? で "未登録" に置き換え
const zip = user.address?.zip ?? "未登録";
console.log(zip); // "未登録"

?? と || の違い

デフォルト値の指定には昔から || が使われてきましたが、?? とは判定基準が異なります。|| は左側が「falsy(偽とみなされる値)」なら右側を使うのに対し、?? は「null または undefined」のときだけ右側を使います。

falsy には 0 や空文字 ""false も含まれます。そのため 0 や空文字を「正しい値」として扱いたい場面では、|| だと意図せず右側に置き換わってしまいます。

script.js
const count = 0;

// || は 0 を falsy とみなすため、右側に置き換わってしまう
console.log(count || 10); // 10(意図しない結果)

// ?? は 0 をそのまま採用する
console.log(count ?? 10); // 0(意図通り)

2つの違いを整理すると次のようになります。「0 や空文字を有効な値として残したい」ときは ?? を選びましょう。

左側の値|| "右" の結果?? "右" の結果
null / undefined“右”“右”
0“右”0
""(空文字)“右”""
false“右”false

使うときに気をつけたいこと

?? と || / && は括弧なしで混在できない

??||&& と同じ式の中でそのまま並べると、優先順位が紛らわしいため構文エラーになります。混ぜて使うときは括弧で意図を明示してください。

script.js
// 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 のオプショナルチェーン も参考にしてください。