--- title: Optional chaining (?.) slug: Web/JavaScript/Reference/Operators/Optional_chaining tags: - Chaining - JavaScript - Language feature - Operator - Optional chaining - Reference translation_of: Web/JavaScript/Reference/Operators/Optional_chaining ---
オプショナルチェイニング演算子 ?. は、接続されたオブジェクトチェーンの深くに位置するプロパティの値を、チェーン内の各参照が正しいかどうかを明示的に確認せずに読み込むことを可能にします。 ?. 演算子の機能は . チェーン演算子と似ていますが、参照が {{glossary("nullish")}} ({{JSxRef("null")}} または {{JSxRef("undefined")}}) の場合にエラーとなるのではなく、式が短絡され undefined が返されるところが異なります。 関数呼び出しで使用すると、与えられた関数が存在しない場合、 undefined を返します。
これは、参照が失われた可能性のある連結されたプロパティにアクセスする時、結果的に短く単純な式になります。また、必要なプロパティの存在が保証されていない場合にオブジェクトのコンテンツを探索するのにも役立ちます。
オプショナルチェイニングは、存在しないルートオブジェクトでは使用できません。if (typeof a == "undefined") のようなチェックを置き換えるものではありません。
obj?.prop obj?.[expr] arr?.[index] func?.(args)
オプショナルチェイニング演算子は、参照や関数が undefined または null である可能性がある場合でも、接続されたオブジェクトの値に簡単にアクセスする手段を提供します。
たとえば、入れ子構造を持つオブジェクト obj を考えましょう。オプショナルチェイニング演算子なしで深い入れ子になったサブプロパティにアクセスするには、次のように、各プロパティ間の参照を確認する必要があります:
let nestedProp = obj.first && obj.first.second;
obj.first.second の値にアクセスする前に、 obj.first の値が null または undefined でないことを確認します。これにより、 obj.first をテストせずに直接 obj.first.second にアクセスしたときに起きるエラーを防ぐことができます。
しかし、オプショナルチェイニング演算子 (?.) を使えば、obj.first.second にアクセスしようとする前に obj.first の状態を明示的にテストする必要がなくなります:
let nestedProp = obj.first?.second;
?. を . の代わりに用いることで、 JavaScript が obj.first.second にアクセスしようとする前に obj.first が null または undefined でないことを暗黙的に確かめるようになります。obj.first が null または undefined であった場合、式が自動的に短絡され、 undefined が返ります。
これは、一時的な変数が作成されないことを除き、次の式と等価です。
let temp = obj.first; let nestedProp = ((temp === null || temp === undefined) ? undefined : temp.second);
存在しない可能性がある関数の呼び出しを試行するときに、オプショナルチェイニングを使うことができます。これはたとえば、ユーザーのデバイス上で使えなかったり、実装が古かったりするために使えなかったりする可能性がある API を使うときに役立ちます。
関数呼び出しでオプショナルチェイニング演算子を用いた場合、メソッドが見つからないときは自動的に undefined が返ります。例外はスローされません。
let result = someInterface.customMethod?.();
注意: 上記のようなプロパティの関数がない場合に、?. を使用すると {{JSxRef("TypeError")}} 例外が発生します (someInterface.customMethod is not a function)。
注意: someInterface 自体が null または undefined の場合にも、{{JSxRef("TypeError")}} 例外が発生します (someInterface is null)。someInterface 自体が null または undefined の可能性がある場合は、次の位置にも ?. を使用しなければなりません。someInterface?.customMethod?.()
コールバックを使う場合や、オブジェクトからメソッドを分割代入を利用して取り出す場合に、存在しない値がある可能性があり、その存在を検証するまで関数として呼び出せません。その場合 ?. を利用することで、検証の必要性を回避できます。
// Written as of ES2019
function doSomething(onContent, onError) {
try {
// ... do something with the data
}
catch (err) {
if (onError) { // Testing if onError really exists
onError(err.message);
}
}
}
// Using optional chaining with function calls
function doSomething(onContent, onError) {
try {
// ... do something with the data
}
catch (err) {
onError?.(err.message); // no exception if onError is undefined
}
}
ブラケット表記法とオプショナルチェイニング演算子を組み合わせることもできます。
let nestedProp = obj?.['prop' + 'Name'];
let object = {};
object?.property = 1; // Uncaught SyntaxError: Invalid left-hand side in assignment
let arrayItem = arr?.[42];
次の例では、マップに存在しない bar メンバの name プロパティを取得しようとしています。したがって、結果は undefined になります。
let myMap = new Map();
myMap.set("foo", {name: "baz", desc: "inga"});
let nameBar = myMap.get("bar")?.name;
式と一緒にオプショナルチェイニング演算子を用いたとき、左側のオペランドが null または undefined である場合にその式は評価されなくなります。
let potentiallyNullObj = null; let x = 0; let prop = potentiallyNullObj?.[x++]; console.log(x); // 0 as x was not incremented
入れ子になったオブジェクトでは、オプショナルチェイニング演算子を何度でも使えます。
let customer = {
name: "Carl",
details: {
age: 82,
location: "Paradise Falls" // detailed address is unknown
}
};
let customerCity = customer.details?.address?.city;
// … this also works with optional chaining function call
let duration = vacations.trip?.getTime?.();
{{JSxRef("Operators/Nullish_Coalescing_Operator", "Null 合体演算子", '', 1)}}はオプショナルチェイニングの後につけることで、存在しない値があった時、既定値をかわりに使うために利用できます。
let customer = {
name: "Carl",
details: { age: 82 }
};
const customerCity = customer?.city ?? "Unknown city";
console.log(customerCity); // Unknown city
| 仕様書 | 状態 | 備考 |
|---|---|---|
| "オプショナルチェイニング" 演算子の提案 | Stage 4 |
{{Compat("javascript.operators.optional_chaining")}}