Optional chaining

これは実験的な機能です。本番で使用する前にブラウザー実装状況をチェックしてください。

The optional chaining operator ?. permits reading the value of a property located deep within a chain of connected objects without having to expressly validate that each reference in the chain is valid. ?. 演算子の機能は . 演算子に似ています。しかし ?. の左側がnullundefinedである場合、エラーが起きる代わりに式が短絡されて undefined が返る点が . 演算子と異なります。 関数呼び出しで ?. 演算子を使うと、関数が存在しない場合に undefined が返ります。

存在しない可能性があるようなチェーンされたプロパティにアクセスする場合、 ?. を使うと短く簡潔な式になります。どのプロパティが必須であるかについて保証がないようなオブジェクトの内容を操作するときにも、 ?. は役立ちます。

Warning! As of August 2019, no environment natively implements this feature. If you use Babel, you may use this plugin to emulate optional chaining.

文法

obj?.prop
obj?.[expr]
func?.(args)

説明

optional chaining 演算子は、参照や関数が undefined か null である可能性があるときに、オブジェクトの値へ簡単にアクセスする方法を提供します。

例として、入れ子構造を持つオブジェクト obj を考えましょう。 optional chaining 演算子を使わない場合、深い入れ子になったサブプロパティへアクセスするには、次のように途中のプロパティが存在することを検証する必要があります。

let nestedProp = obj.first && obj.first.second;

obj.first.second へアクセスする前に、obj.first の値が nullundefined でないことが確認されます。これによって、( obj.first の確認なしに )直接 obj.first.second へアクセスしたときに起きるエラーを防ぐことができます。

しかし、optional chaining 演算子 (?.) を使えば、 obj.first.second へアクセスする前に obj.first の状態を明示的に確認する必要がなくなります。

let nestedProp = obj.first?.second;

?. を . の代わりに用いることで、JavaScriptは obj.first.second へアクセスする前に obj.first が null や undefined でないことを確かめるようになります。obj.first が null や undefined であった場合、式が自動的に短絡され、 undefined が返ります。

optional chaining 演算子を用いた式は次の式と等価です。

let nestedProp = (obj.first == null ? undefined : obj.first.second);

関数呼び出しで optional chaining 演算子を使う

存在しない可能性があるメソッドを呼び出そうとするときに optional chaining 演算子を使えます。例えば次のような場合に optional chaining 演算子が便利です。

  • 実装のバージョンによって利用不可能なAPIのメソッドを使うとき。
  • ユーザーのデバイス特有の機能に関するAPIのメソッドを使うとき。

関数呼び出しで optional chaining 演算子を用いた場合、メソッドが見つからないときは自動的に undefined が返ります。例外はスローされません。

let result = someInterface.customMethod?.();

Note: 存在するがメソッドでないプロパティに対して ?. を使うと、例外 TypeError がスローされます (x.y is not a function) 。

Dealing with optional callbacks or event handlers

If you use callbacks or fetch methods from an object with a destructuring assignment, you may have non-existent values that you cannot call as functions unless you have tested their existence. Using ?., you can avoid this extra test:

// 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
  }
}

式と一緒に optional chaining 演算子を使う

ブラケット表記法と optional chaining 演算子を組み合わせることもできます。

let nestedProp = obj?.['prop' + 'Name'];

基本的な例

次の例では、マップ myMap に存在しない bar メンバに対して name プロパティを取得しようとしています。TypeError はスローされず、 nameBar に undefined が代入されます。

let myMap = new Map();
myMap.set("foo", {name: "baz", desc: "inga"});

let nameBar = myMap.get("bar")?.name;

Short-circuiting evaluation

式と一緒に optional chaining 演算子を用いたとき、左側のオペランドが null または undefined である場合にその式は評価されなくなります。

次の例では、 ?. の左側の potentiallyNullObj が null であるため、 x++ が評価されません。

let potentiallyNullObj = null;
let x = 0;
let prop = potentiallyNullObj?.[x++];

console.log(x); // 0 as x was not incremented

Stacking the optional chaining operator

ネストされたオブジェクトでは、 optional chaining 演算子を何度でも使えます。

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?.();

仕様

Specification Status Comment
Proposal for the "optional chaining" operator Stage 3

ブラウザ実装状況

Update compatibility data on GitHub
デスクトップモバイルサーバー
ChromeEdgeFirefoxInternet ExplorerOperaSafariAndroid webviewAndroid 版 ChromeAndroid 版 FirefoxAndroid 版 OperaiOSのSafariSamsung InternetNode.js
Optional chaining operator (?.)
実験的
Chrome 未対応 なしEdge 未対応 なしFirefox 未対応 なしIE 未対応 なしOpera 未対応 なしSafari ? WebView Android 未対応 なしChrome Android 未対応 なしFirefox Android 未対応 なしOpera Android 未対応 なしSafari iOS ? Samsung Internet Android 未対応 なしnodejs 未対応 なし

凡例

未対応  
未対応
実装状況不明  
実装状況不明
実験的。動作が変更される可能性があります。
実験的。動作が変更される可能性があります。

関連情報