JavaScript | ES6+ 文法:その他の ES6+ 機能 – Optional chaining

JavaScript JavaScript
スポンサーリンク

Optional chaining とは何か(まずイメージから)

Optional chaining(オプショナルチェイニング)は
?. という記号で書く、「存在しないかもしれないプロパティに安全にアクセスするための仕組み」 です。

const user = { profile: { name: "Alice" } };

console.log(user.profile?.name); // "Alice"
console.log(user.address?.city); // undefined(エラーにならない!)
JavaScript

普通に user.address.city と書くと、addressundefined のときに
「Cannot read properties of undefined」 というエラーで落ちます。

?. を使うと、
「もし左側が nullundefined なら、そこで止めて undefined を返す」
という安全な動きになります。

ここが重要です。
「あるかもしれない、ないかもしれない」深いプロパティにアクセスするときは、とりあえず ?. を思い出す
これだけで、かなりの「よくあるエラー」を避けられます。


なぜ Optional chaining が必要なのか

よくあるエラー:「undefined の何かを読もうとして落ちる」

JSON や API からのデータを扱っていると、
こんなコードを書きたくなります。

const city = user.address.city;
JavaScript

でも user.address が存在しない(undefined)場合、

Cannot read properties of undefined (reading 'city')
JavaScript

のようなエラーになってしまいます。

こういうエラーは、実務では本当によく出ます。

旧式の対処:if を何重にも書く

昔は、こうやってガードしていました。

let city;

if (user && user.address && user.address.city) {
  city = user.address.city;
} else {
  city = "不明";
}
JavaScript

動きますが、見た目がかなりつらいですよね。
ネストが深くなるほど、&& の地獄になっていきます。

Optional chaining を使うとどうなるか

同じことを Optional chaining で書くと、こうなります。

const city = user.address?.city ?? "不明";
JavaScript
  • user.address?.city
    address があれば city を読む
    → なければ undefined を返す(エラーにはしない)
  • ?? "不明"
    → 左が null / undefined なら "不明" を使う

ここが重要です。
「深いところまであるかどうか分からないデータ」には、?.?? を組み合わせるのが ES2020 以降の定番パターン です。


基本文法:obj?.prop と obj?.[key] と func?.()

プロパティアクセス:obj?.prop

一番よく使うのがこれです。

const user = { profile: { name: "Alice" } };

console.log(user.profile?.name); // "Alice"
console.log(user.address?.city); // undefined(エラーにならない)
JavaScript

user.address?.city の場合、

  • user.addressnull / undefined → 全体が undefined
  • それ以外(オブジェクトなど) → その city を読む

という動きになります。

ブラケット記法:obj?.[key]

キー名が変数に入っている場合や、
スペースを含むプロパティ名などにはブラケット記法を使います。

const data = { settings: { "user-name": "Alice" } };

const key = "user-name";

console.log(data.settings?.[key]);      // "Alice"
console.log(data.missing?.[key]);       // undefined(エラーにならない)
console.log(data.settings?.["age"]);    // undefined
JavaScript

obj?.[key] は、
「obj が null/undefined なら undefined、それ以外なら obj[key]」という動きです。

関数呼び出し:func?.()

「あるかどうか分からない関数」を呼ぶときにも使えます。

const callbacks = {
  onClick: () => console.log("クリックされました"),
};

callbacks.onClick?.();      // あれば呼ぶ
callbacks.onHover?.();      // なくてもエラーにならない
JavaScript

func?.() は、

  • func が関数なら呼ぶ
  • funcnull / undefined なら何もせず undefined を返す

という振る舞いです。

ここが重要です。
「オプションで渡されるコールバック」「あってもなくてもよいイベントハンドラ」には func?.() が刺さる
「もしあれば」という意図がコードからも一目瞭然です。


ネストが深いときにこそ威力を発揮する

典型例:API レスポンスの安全アクセス

API からこんなデータが返ってくるとします。

const user = {
  profile: {
    name: "Alice",
    address: {
      city: "Tokyo",
    },
  },
};
JavaScript

でも、環境によっては address がなかったり、
profile 自体がなかったりするかもしれません。

昔なら:

let city;

if (
  user &&
  user.profile &&
  user.profile.address &&
  user.profile.address.city
) {
  city = user.profile.address.city;
} else {
  city = "不明";
}
JavaScript

Optional chaining + null 合体演算子なら:

const city = user.profile?.address?.city ?? "不明";
JavaScript

読みやすさの差は、かなり大きいです。

チェーンの途中で止まるイメージ

user.profile?.address?.city の評価は、ざっくりこうです。

  1. user.profile を読む(ここでエラーにはならない前提)
  2. その結果が null / undefined なら、そこで全体を undefined にして止める
  3. そうでなければ .address に進む
  4. また ?. があるので、addressnull / undefined なら止める
  5. そうでなければ .city を読む

ここが重要です。
?. は「安全な橋渡し」みたいなもの。
その地点の手前で川(null/undefined)が切れていたら、それ以上向こうには渡らない。


Optional chaining と他の演算子の組み合わせ

?. と ??(null 合体演算子)

Optional chaining で undefined になってしまったときの「代わりの値」を指定するのに、?? が使えます。

const city = user.profile?.address?.city ?? "不明";
JavaScript

?? の左側が null または undefined のときだけ、右側が使われます。
空文字や 0 などはそのまま有効な値として扱われます。

const config = { retries: 0 };

const count1 = config.retries || 3; // 0 が「偽」とみなされて 3 になる
const count2 = config.retries ?? 3; // 0 をそのまま採用 → 0
JavaScript

?. と || を混ぜたくなるときの注意

|| は「偽っぽい値(0, “”, false など)も全部ダメ扱い」するので、
設定のデフォルト値などでは、?? の方が意図に合っていることが多いです。

誤解を避けるためにも、
「不在(null/undefined)にだけデフォルト値を入れたい」ときは ??
と覚えておくのがおすすめです。


Optional chaining の落とし穴・注意点

何でもかんでも ?. を付ければいいわけではない

user?.profile?.name のように、
「あるかどうか本当に分からない」場所に使うのは良いのですが、

全部にクセで ?. を付けてしまうと、
バグの早期発見を妨げることがあります。

例えば、本来絶対にいるはずの userundefined になってしまったとき、

  • user.name → そこでエラーになってすぐ気付ける
  • user?.nameundefined になってしまい、どこでミスったのか分かりにくくなる

ということが起きます。

ここが重要です。
Optional chaining は「本当に Optional なもの」にだけ使う。
「必須のもの」に使うとバグを隠すことになる。

左側が「必ずある」なら、普通の . でいい

例えば:

const user = getUser(); // ここが「必ず User を返す」契約なら

console.log(user?.name); // よりも
console.log(user.name);  // のほうがいい(おかしいときにすぐ落ちる)
JavaScript

設計として「必ずあるはず」のものには、
あえて Optional chaining を使わず、
異常時にはエラーになってもらった方が、デバッグがしやすくなります。


短い例題で手を動かしてみる

例1:ネストされた配列・オブジェクト

const data = {
  items: [
    { id: 1, name: "A" },
    { id: 2, name: "B" },
  ],
};

const firstName = data.items?.[0]?.name ?? "なし";
const thirdName = data.items?.[2]?.name ?? "なし";

console.log(firstName); // "A"
console.log(thirdName); // "なし"
JavaScript

items?.[2]?.name の部分に注目してください。

  • items がなければ → undefined
  • [2] がなければ → undefined
  • .name がなければ → undefined

どこで途切れても、全体が undefined になり、
最終的に ?? "なし" が適用されます。

例2:存在するか分からないイベントハンドラ

function runCallbacks(callbacks) {
  callbacks.onStart?.();
  console.log("メイン処理");
  callbacks.onFinish?.();
}

runCallbacks({
  onStart() {
    console.log("開始");
  },
  // onFinish は省略
});
// 開始
// メイン処理
JavaScript

onFinish がなくてもエラーにならず、
「あるときだけ実行される」のが Optional chaining の美味しいところです。


まとめ

Optional chaining(?.)の本質は、
null / undefined かもしれないものに、安全にアクセスするためのショートカット」 です。

押さえておきたいポイントは:

  • obj?.prop / obj?.[key] / func?.() の 3 形態がある
  • 途中で null / undefined に遭遇したら、そこで評価を止めて undefined を返す(エラーにしない)
  • 深くネストしたオブジェクト・API レスポンス・オプションのコールバックなどで強力
  • ??(null 合体演算子)と組み合わせて「デフォルト値」を書くのが定番
  • なんでも ?. にするとバグを隠すので、「本当に存在が optional な場合」にだけ使う

まずは、

  • 素直に書くと Cannot read properties of undefined が出てしまうコード
  • user && user.address && user.address.city みたいなガードだらけのコード

を一つ見つけて、それを

const city = user.address?.city ?? "不明";
JavaScript

のように書き直してみてください。

その一歩で、Optional chaining の「気持ちよさ」がかなりはっきり見えてきます。

タイトルとURLをコピーしました