2023年4月23日

ナルリッシュ・コアレシング演算子 '??'

最近の追加機能
これは言語への最近の追加機能です。古いブラウザでは、ポリフィルが必要になる場合があります。

ナルリッシュ・コアレシング演算子は、2つの疑問符 `??` として記述されます。

`null` と `undefined` を同様に扱うため、この記事では特別な用語を使用します。簡潔にするため、`null` でも `undefined` でもない値を「定義済み」と呼びます。

`a ?? b` の結果は次のとおりです。

  • `a` が定義済みの場合、`a`。
  • `a` が定義されていない場合、`b`。

言い換えると、`??` は、最初の引数が `null/undefined` でない場合、最初の引数を返します。そうでない場合は、2番目の引数を返します。

ナルリッシュ・コアレシング演算子は、まったく新しいものではありません。単に、2つの値のうち最初の「定義済み」値を取得するための便利な構文です。

`result = a ?? b` は、既に知っている演算子を使用して次のように書き直すことができます。

result = (a !== null && a !== undefined) ? a : b;

これで、`??` の動作が完全に明確になったはずです。それでは、`??` が役立つ場面を見てみましょう。

`??` の一般的なユースケースは、デフォルト値を提供することです。

たとえば、ここでは、`user` の値が `null/undefined` でない場合は `user` を、そうでない場合は `Anonymous` を表示します。

let user;

alert(user ?? "Anonymous"); // Anonymous (user is undefined)

名前が `user` に割り当てられている例を次に示します。

let user = "John";

alert(user ?? "Anonymous"); // John (user is not null/undefined)

`??` のシーケンスを使用して、`null/undefined` ではないリストから最初の値を選択することもできます。

たとえば、`firstName`、`lastName`、または `nickName` の変数にユーザーデータがあるとします。ユーザーが対応する値を入力しなかった場合、これらはすべて定義されていない可能性があります。

これらの変数のいずれかを使用してユーザー名を表示するか、すべてが `null/undefined` の場合は「Anonymous」を表示したいと考えています。

`??` 演算子を使用してみましょう。

let firstName = null;
let lastName = null;
let nickName = "Supercoder";

// shows the first defined value:
alert(firstName ?? lastName ?? nickName ?? "Anonymous"); // Supercoder

|| との比較

OR 演算子 `||` は、前の章で説明したように、`??` と同じように使用できます。

たとえば、上記のコードでは `??` を `||` に置き換えても、同じ結果が得られます。

let firstName = null;
let lastName = null;
let nickName = "Supercoder";

// shows the first truthy value:
alert(firstName || lastName || nickName || "Anonymous"); // Supercoder

歴史的に、OR 演算子 `||` は先に存在していました。JavaScript の最初から存在していたため、開発者は長い間、このような目的で使用していました。

一方、ナルリッシュ・コアレシング演算子 `??` は最近になって JavaScript に追加され、その理由は人々が `||` にあまり満足していなかったためです。

重要な違いは次のとおりです。

  • `||` は最初の真偽値を返します。
  • `??` は最初の定義済み値を返します。

言い換えると、`||` は `false`、`0`、空文字列 `""`、`null/undefined` を区別しません。これらはすべて同じです — 偽値です。これらのいずれかが `||` の最初の引数である場合、結果は2番目の引数になります。

しかし実際には、変数が `null/undefined` の場合にのみデフォルト値を使用したい場合があります。つまり、値が実際に不明/設定されていない場合です。

たとえば、次のことを検討してください。

let height = 0;

alert(height || 100); // 100
alert(height ?? 100); // 0
  • `height || 100` は、`height` が偽値であるかどうかをチェックし、`0` は偽値です。
    • したがって、`||` の結果は2番目の引数 `100` になります。
  • `height ?? 100` は、`height` が `null/undefined` であるかどうかをチェックし、そうではありません。
    • したがって、結果は `height` そのまま、つまり `0` です。

実際には、高さ0は多くの場合有効な値であり、デフォルト値で置き換えるべきではありません。そのため、`??` はまさに正しい動作をします。

優先順位

`??` 演算子の優先順位は `||` と同じです。MDN の表ではどちらも `3` と等しくなります。

つまり、`||` と同様に、ナルリッシュ・コアレシング演算子 `??` は `=` と `?` よりも前に評価されますが、`+`、`*` などの他のほとんどの演算子の後です。

そのため、次のような式では括弧を追加する必要がある場合があります。

let height = null;
let width = null;

// important: use parentheses
let area = (height ?? 100) * (width ?? 50);

alert(area); // 5000

そうでない場合、括弧を省略すると、`*` の優先順位が `??` よりも高いため、先に実行され、結果が正しくなくなります。

// without parentheses
let area = height ?? 100 * width ?? 50;

// ...works this way (not what we want):
let area = height ?? (100 * width) ?? 50;

&& または || との ?? の使用

安全上の理由から、JavaScript は、優先順位を括弧で明示的に指定しない限り、`??` を `&&` と `||` 演算子と一緒に使用することを禁止しています。

次のコードは構文エラーを引き起こします。

let x = 1 && 2 ?? 3; // Syntax error

この制限は確かに議論の余地がありますが、人々が `||` から `??` に切り替える際にプログラミングミスを回避するために、言語仕様に追加されました。

これを回避するには、明示的に括弧を使用します。

let x = (1 && 2) ?? 3; // Works

alert(x); // 2

まとめ

  • ナルリッシュ・コアレシング演算子 `??` は、リストから最初の「定義済み」値を選択する簡単な方法を提供します。

    変数にデフォルト値を割り当てるために使用されます。

    // set height=100, if height is null or undefined
    height = height ?? 100;
  • `??` 演算子の優先順位は非常に低く、`?` と `=` よりもわずかに高いだけです。そのため、式で使用する場合には括弧を追加することを検討してください。

  • 明示的な括弧を使用しない限り、`||` または `&&` と一緒に使用することは禁止されています。

チュートリアルマップ

コメント

コメントする前にこれをお読みください…
  • 改善すべき点があれば、コメントする代わりにGitHub の issue を送信するか、プルリクエストを送信してください。
  • 記事の内容が理解できない場合は、詳しく説明してください。
  • コードを数語挿入するには `<code>` タグを使用し、複数行の場合は `<pre>` タグで囲み、10 行を超える場合はサンドボックス (plnkrjsbincodepen…) を使用してください。