Menu
日本語
Playgroundで試す

JavaScript オプショナルチェーン(?.)の使い方まとめ

?. 演算子を使えば、null や undefined で落ちることなく、ネストされたオブジェクトや配列、メソッドに安全にアクセスできます。

問題点:ネストしたプロパティへのアクセスは壊れやすい

ネストしたオブジェクトの中身を取り出す処理は、普段は問題なく動きます。ただし、途中の階層が存在しなかった瞬間にエラーになります。

index.js
Output
Click Run to see the output here.

user.addressundefined なので、そこから .city を読み取ろうとすると TypeError: Cannot read properties of undefined が投げられます。APIレスポンス、パース済みのJSON、DOMクエリなど、実際のデータには存在するかどうか分からないフィールドが山ほどあります。そして、各階層ごとに防御的なチェックを書いていると、コードはすぐにごちゃごちゃしてきます。

const city = user && user.address && user.address.city;

読めなくはないですが、ネストが2階層までの話。4階層にもなると地獄です。こういうときに ?. 演算子を使うとスッキリ書けます。

?. は null と undefined で短絡評価される

JavaScript のオプショナルチェーン演算子(?.)は、手前の値が null でも undefined でもないときだけプロパティを読み取ります。もしそうでなければ、式全体が undefined になってそこで評価が止まります。

index.js
Output
Click Run to see the output here.

1行目は普通に name を取り出せます。2行目では user.addressundefined なので、そこで中断し、チェーンの残りは評価されません。3行目は本来なら undefined に対して .toUpperCase() を呼ぶことになってエラーですが、?. のおかげで全体が静かに undefined になります。

イメージとしては、?. は「自分の手前が nullundefined だったら諦めて undefined を返す。そうじゃなければ処理を続ける」という意味だと覚えておけばOKです。

配列や関数呼び出しにも使えるオプショナルチェーン

書き方は3パターンありますが、考え方はどれも同じです。

index.js
Output
Click Run to see the output here.
  • 配列アクセスや動的プロパティアクセスには ?.[...] を使います。
  • 関数かどうか分からないものを呼び出すときは ?.() です。
  • 通常のプロパティアクセスなら ?.name ですね。

この3つはいずれも同じようにショートサーキット(短絡評価)します。たとえば user?.notAMethod?.() は、notAMethod が存在しなくてもエラーになりません。2つ目の ?.undefined を検知した時点で処理が止まるからです。

この書き方は、オプショナルなコールバックを扱うときに特に便利です。

index.js
Output
Click Run to see the output here.

if (typeof onDone === "function") のようなガード節を呼び出しのたびに書く必要はもうありません。

ショートサーキットが発動するのは nullundefined だけ

ここが意外と勘違いしやすいポイントです。?. が反応するのは nullish な値だけ。0""falseNaN といった他の falsy な値は、オブジェクトとして普通にチェーンできてしまいます(オートボクシングが効く範囲で、という話ですが):

index.js
Output
Click Run to see the output here.

data.count0 です。falsy ではありますが nullish ではないので、?.toFixed(2) がそのまま実行され "0.00" が返ります。これを && と比べてみましょう。

index.js
Output
Click Run to see the output here.

&& 版が 0 を返すのは、data.count が falsy なので短絡評価が効くからです。一方で ?. 版が "0.00" を返すのは、0 が nullish ではないからですね。0 でも処理を止めたいなら && が正解。「値が存在しないときだけ止めたい」のであれば、?. の出番です。

? を置く位置で挙動が変わる

オプショナルチェーン演算子 ?. が守ってくれるのは、その 直前 の値だけです。後ろではありません。なので、欠けている可能性がある階層に付けるのがポイントです。

index.js
Output
Click Run to see the output here.

ここでは 3 つともきちんと動きますが、これは値が欠けていないからです。もし config.serverundefined になる可能性があるなら、config.server?.host と書く必要があります。server の手前に ?. を置いても意味がありません。問題は、存在しない server から .host を読もうとすることだからです。

コツとしては、その 手前 にある値が本当に null や undefined になり得る箇所だけ?. を付けることです。「念のため」と全部のドットに ?. を付けて回ると、バグを隠してしまう上にコードもノイズだらけになります。

?. 経由での代入はできない

オプショナルチェーンは読み取り専用です。代入の左辺には使えません。

user?.address?.city = "Paris";   // SyntaxError

考えてみれば当然の挙動ですよね。undefined のプロパティに代入するって、そもそも意味が通らないわけですから。もし親オブジェクトが存在するときだけ値をセットしたい場合は、こんなふうに書き下してあげましょう。

index.js
Output
Click Run to see the output here.

どんなときに使う? 逆に使わない方がいいのは?

?. が真価を発揮するのは、値が「本当に存在しないこともある」ケースです。

  • フィールドが含まれたり含まれなかったりする API レスポンス
  • DOM の取得処理: document.querySelector(".banner")?.remove()
  • 渡されるとは限らないコールバック: options.onError?.(err)
  • 途中の結果が null になり得るライブラリのメソッドチェーン

逆に、値が「絶対に存在するはず」のところに ?. を使うのは間違いです。エラーを黙らせるために安易に ?. を撒くと、「42 行目で TypeError」という見つけやすいバグが、「3 つ先の関数で変数がなぜか undefined」という静かなバグに化けてしまいます。本来あるべきものが無いなら、堂々と例外を投げさせましょう。スタックトレースはむしろありがたい味方です。

実践的な例

欠損があり得る API レスポンスから値を取り出す例を見てみましょう。

index.js
Output
Click Run to see the output here.

?. は不確かさを1段ずつ処理してくれます。欠けている値があっても、avatarUrl はきれいに undefined になります。onClick?.() は、ハンドラーがあれば呼び出し、なければ何もしません。

displayName の行にある ?? にも注目してみてください。これはこのパターンのもう半分です。?. は値が欠けているときに undefined を返してくれますが、??0"" のような正当な falsy 値を誤って弾かずに、デフォルト値を差し込むためのものです。

次は: Nullish 合体演算子

?.?? は、同じ発想を別々の問題に適用したものです。どちらも nullundefined だけを「欠けている」とみなし、それ以外の falsy 値はそのまま尊重します。次の章では、?? でまともなデフォルト値を扱う方法と、|| が長年こっそり間違った挙動をしてきた理由を見ていきます。

よくある質問

JavaScriptの ?. は何をする演算子ですか?

?. は、直前の値が nullundefined でないときだけ、プロパティ・配列の要素・メソッドにアクセスする演算子です。もし nullundefined だった場合はそこで式全体がショートサーキットし、エラーを投げずに undefined を返します。例えば user?.address?.city と書いておけば、useraddress が存在しなくても落ちません。

オプショナルチェーンはどんな場面で使うべき?

「値が存在しないこともあり得る」と明確にわかっているときに使うのがベストです。たとえばオプショナルなフィールドを含むAPIレスポンス、見つかるとは限らないDOM要素、渡されるかどうかわからないコールバック関数などですね。逆に、本来必ず存在しているはずの値に ?. を付けてバグをごまかすのはNGです。そういうケースでは、値が無いこと自体が重要なサインなので、素直にエラーとして見えるようにしておくべきです。

?. と && はどう違いますか?

多くの場合は同じ結果になりますが、挙動の条件が違います。?. はショートサーキットするのが nullundefined のときだけ。一方 &&0''false など、あらゆるfalsy値でショートサーキットします。たとえば obj && obj.countcount0 のときにも 0 を返しますが、これは意図せずfalsy判定が走ってしまうことがある書き方です。obj?.count なら null / undefined のときだけ止まるので、0 や空文字は素直にそのまま返ってきます。

配列や関数呼び出しにもオプショナルチェーンは使えますか?

使えます。arr?.[0] と書けば配列のインデックスに安全にアクセスできますし、fn?.() なら関数が存在するときだけ呼び出せます。ルールは同じで、?. の左側が null または undefined なら式全体は undefined になり、その後ろの処理は一切実行されません。

Coddyでコードを学ぼう

始める