|
| 1 | +# NULL合体演算子(Nullish coalescing operator) '??' |
| 2 | + |
| 3 | +[recent browser="new"] |
| 4 | + |
| 5 | +NULL合体演算子 `??` はリストの中から最初の "定義済み" 変数を選択するための短縮構文です。 |
| 6 | + |
| 7 | +`a ?? b` の結果は: |
| 8 | +- `a` が `null` あるいは `undefined` でなければ `a`, |
| 9 | +- それ以外の場合は `b`. |
| 10 | + |
| 11 | +したがって、`x = a ?? b` は以下と同等です: |
| 12 | + |
| 13 | +```js |
| 14 | +x = (a !== null && a !== undefined) ? a : b; |
| 15 | +``` |
| 16 | + |
| 17 | +次はより長い例です。 |
| 18 | + |
| 19 | +想像してください、ユーザがいて、性、名、ニックネーム用の変数 `firstName`, `lastName`, `nickName` があるとします。ユーザが何も入力しなければ、それらはすべて undefined になるかもしれません。 |
| 20 | + |
| 21 | +ユーザ名を表示します: 3つの変数のいずれか、あるいは設定されていない場合は "Anonymous" とします。 |
| 22 | + |
| 23 | +`??` 演算子を使って最初に定義されたものを選択しましょう。: |
| 24 | + |
| 25 | +```js run |
| 26 | +let firstName = null; |
| 27 | +let lastName = null; |
| 28 | +let nickName = "Supercoder"; |
| 29 | + |
| 30 | +// 最初の null/undefined でない値を表示します |
| 31 | +*!* |
| 32 | +alert(firstName ?? lastName ?? nickName ?? "Anonymous"); // Supercoder |
| 33 | +*/!* |
| 34 | +``` |
| 35 | +
|
| 36 | +## || との比較 |
| 37 | +
|
| 38 | +OR `||` 演算子は `??` と同じ方法で利用することができます。[前のチャプター](info:logical-operators#or-finds-the-first-truthy-value) で説明したように、実際、上のコードでは `??` を `||` に置き換えることができ、同じ結果を得ることができます。 |
| 39 | +
|
| 40 | +重要な違いは次の通りです: |
| 41 | +- `||` は最初の *真* の値を返します。 |
| 42 | +- `??` は最初の *定義済み* の値を返します。 |
| 43 | +
|
| 44 | +これは、`null/undefined` を `0` とは別に扱いたい場合、非常に重要です。 |
| 45 | +
|
| 46 | +例えば、次を考えてみましょう: |
| 47 | +
|
| 48 | +```js |
| 49 | +height = height ?? 100; |
| 50 | +``` |
| 51 | +
|
| 52 | +`height` が未定義であれば、`100` が設定されます。 |
| 53 | +
|
| 54 | +`||` と比較してみましょう: |
| 55 | +
|
| 56 | +```js run |
| 57 | +let height = 0; |
| 58 | + |
| 59 | +alert(height || 100); // 100 |
| 60 | +alert(height ?? 100); // 0 |
| 61 | +``` |
| 62 | +
|
| 63 | +ここでは、`height || 100` は 高さゼロを `null` や `undefined` あるいは他の偽の値と同様に未定義として扱っています。そのため、結果は `100` です。 |
| 64 | +
|
| 65 | +`height ?? 100` は `height` がまさに `null` あるいは `undefined` の場合にのみ `100` を返します。したがって、`alert` は高さの値 `0` を "そのまま" 表示します。 |
| 66 | +
|
| 67 | +どちらの振る舞いがよいかはユースケースによります。高さゼロは有効な値の場合、`??` の方が好ましいです。 |
| 68 | +
|
| 69 | +## 優先順位 |
| 70 | +
|
| 71 | +`??` の順位は低めです: [MDN テーブル](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Operator_Precedence#Table) の `5` です。 |
| 72 | +
|
| 73 | +したがって、`??` は他の多くの演算子の後で、`=` と `?` の前に評価されます。 |
| 74 | +
|
| 75 | +複雑な式で `??` を用いて値を選択する必要がある場合は括弧を用いることを検討してください: |
| 76 | +
|
| 77 | +```js run |
| 78 | +let height = null; |
| 79 | +let width = null; |
| 80 | + |
| 81 | +// 重要: 括弧を使用します |
| 82 | +let area = (height ?? 100) * (width ?? 50); |
| 83 | + |
| 84 | +alert(area); // 5000 |
| 85 | +``` |
| 86 | +
|
| 87 | +そうでない場合、括弧を省略すると `*` は `??` よりも優先度が高いため、最初に実行されます。 |
| 88 | +
|
| 89 | +これば次のように動くことを意味します: |
| 90 | +
|
| 91 | +```js |
| 92 | +// 恐らくこれは正しくない計算でしょう |
| 93 | +let area = height ?? (100 * width) ?? 50; |
| 94 | +``` |
| 95 | +
|
| 96 | +また、ここには関連する言語レベルの制限もあります。 |
| 97 | +
|
| 98 | +**安全上の理由により、`&&` や `||` 演算子と一緒に `??` を用いることは禁止されています。** |
| 99 | +
|
| 100 | +次のコードは構文エラーになります: |
| 101 | +
|
| 102 | +```js run |
| 103 | +let x = 1 && 2 ?? 3; // Syntax error |
| 104 | +``` |
| 105 | +
|
| 106 | +この制限には当然議論の余地がありますが、人々が `||` から `??` に切り替え始めるときに、プログラミングのミスを避ける目的で言語仕様に追加されました。 |
| 107 | +
|
| 108 | +回避するには明示的に括弧を使用します: |
| 109 | +
|
| 110 | +```js run |
| 111 | +*!* |
| 112 | +let x = (1 && 2) ?? 3; // 動作します |
| 113 | +*/!* |
| 114 | + |
| 115 | +alert(x); // 2 |
| 116 | +``` |
| 117 | +
|
| 118 | +## サマリ |
| 119 | +
|
| 120 | +- Null合体演算子 `??` は一覧から "定義済み" の値を選択するための簡単な方法を提供します。 |
| 121 | +
|
| 122 | + 変数にデフォルト値を代入するために使用されます: |
| 123 | +
|
| 124 | + ```js |
| 125 | + // height が null あるいは undefined であれば height=100 を設定します |
| 126 | + height = height ?? 100; |
| 127 | + ``` |
| 128 | +
|
| 129 | +- 演算子 `??` は優先度が低く、`?` や `=` よりも少し高い程度です。 |
| 130 | +- 明示的な括弧なしに `||` や `&&` と一緒に利用することは禁止されています。 |
0 commit comments