演算子の優先順位
========

**演算子の優先順位**は、演算子が互いにどのように解釈されるかを決定します。優先度の高い演算子は、優先度の低い演算子のオペランドになります。

試してみましょう
--------

優先度と結合性
-------

以下の表現で記述できる式を考えてみましょう。なお、`OP1` と `OP2` は演算子に置き換わります。


```js
a OP1 b OP2 c
```


`OP1` と `OP2` の優先順位（下記の一覧表を参照）が異なる場合は、優先順位の高い演算子が先に実行され、結合性は関係ありません。コードの中で加算が先に書かれているにもかかわらず、乗算の方が加算よりも優先順位が高く、先に実行されていることを確認してください。


```js
console.log(3 + 10 \* 2); // 23 を出力
console.log(3 + 10 \* 2); // 括弧の優先順位が高いので、23 を出力
console.log((3 + 10) \* 2); // 括弧が順位を変更するので 26 を出力
```


左結合（左から右）は `(a OP1 b) OP2 c` のように処理されることであり、右結合（右から左）は `a OP1 (b OP2 c)` のように解釈されることです。代入演算子は右結合なので、このように書くことができます。


```js
a = b = 5; // a = (b = 5); と書いたのと同じ
```


これで、`a` と `b` が 5 の値を得るという期待通りの結果を得ることができます。これは代入演算子が代入した値を返すためです。まず `b` に 5 が設定されます。そして `a` にも、代入演算子の右オペランドである `b = 5` が返す 5 が設定されるのです。

他の例として、べき乗演算子だけが右結合性を持ちますが、他の算術演算子は左結合性を持ちます。興味深いのは、結合性や優先順位に関係なく、評価の順序は常に左から右になることです。

|  |  |
| --- | --- |
| コード | 出力結果 |
| 
```js
function echo(name, num) {
    console.log("Evaluating the " + name + " side");
    return num;
}
// 除算演算子 (/) の場合
console.log(echo("left", 6) / echo("right", 2));
```

 | 
```
Evaluating the left side
Evaluating the right side
3
```

 |
| 
```js
function echo(name, num) {
    console.log("Evaluating the " + name + " side");
    return num;
}
// べき乗演算子 (\*\*) の場合
console.log(echo("left", 2) \*\* echo("right", 3));
```

 | 
```
Evaluating the left side
Evaluating the right side
8
```
 |

結合性の違いは、同じ優先順位の演算子が複数存在する場合に現れます。上の例のように演算子が一つだけの場合や、演算子の優先順位が異なる場合は、結合性は出力に影響を与えません。下の例では、同じ演算子が複数使われている場合に、結合性が出力結果にどのような影響を与えるかを見てみましょう。

|  |  |
| --- | --- |
| コード | 出力結果 |
| 
```js
function echo(name, num) {
    console.log("Evaluating the " + name + " side");
    return num;
}
// 除算演算子 (/) の場合
console.log(echo("left", 6) / echo("middle", 2) / echo("right", 3));
```

 | 
```
Evaluating the left side
Evaluating the middle side
Evaluating the right side
1
```

 |
| 
```js
function echo(name, num) {
    console.log("Evaluating the " + name + " side");
    return num;
}
// べき乗演算子 (\*\*) の場合
console.log(echo("left", 2) \*\* echo("middle", 3) \*\* echo("right", 2));
```

 | 
```
Evaluating the left side
Evaluating the middle side
Evaluating the right side
512
```

 |
| 
```js
function echo(name, num) {
    console.log("Evaluating the " + name + " side");
    return num;
}
// 左と中央の間のべき乗を括弧で囲んだ場合
console.log((echo("left", 2) \*\* echo("middle", 3)) \*\* echo("right", 2));
```
 | 
```
Evaluating the left side
Evaluating the middle side
Evaluating the right side
64
```
 |

上記のコードを見てください。`6 / 3 / 2` は、除算が左結合なので `(6 / 3) / 2` と同じになります。一方で、べき乗は右結合なので、`2 ** 3 ** 2` は `2 ** (3 ** 2)` と同じになります。したがって、 `(2 ** 3) ** 2` とすると上記の表にある通り、演算順序が変わって結果が 64 になります。

優先順位は結合度よりも優先されることを忘れないでください。そのため、割り算とべき乗を交ぜた場合、べき乗は割り算よりも先に計算されます。例えば `2 ** 3 / 3 ** 2` の結果は 0.8888888888888888 となります。これは `(2 ** 3) / (3 ** 2)` と同じだからです。

### グループ化と短絡評価の注意

下記の表では、**グループ化**が最上位の優先順位を持つものとして挙げられています。しかし、特に短絡が発生する場合は、グループ化記号 `( … )` の中の式が最初に評価されるとは限りません。

短絡評価は、条件付き評価を表す用語です。例えば、`a && (b + c)` という式において、`a` が偽値である場合、従属式である `(b + c)` は括弧で囲まれていても評価されません。この論理的分離演算子 ("OR") は「短絡的」といえるでしょう。論理的分離演算子の他にも、ほかに短絡が発生する演算子には、論理的結合 ("AND") 演算子、Null 合体演算子、オプション連鎖演算子、条件演算子があります。以下に例を示します。


```js
a || b \* c; // 最初に `a` を評価し、 `a` が「真値」であれば `a` を出力
a && b < c; // 最初に `a` を評価し、 `a` が「偽値」であれば `a` を出力
a ?? (b || c); // 最初に `a` を評価し、 `a` が `null` または `undefined` でなければ `a` を出力
a?.b.c; // 最初に `a` を評価し、 `a` が `null` または `undefined` であれば `undefined` を出力
```

例
-


```js
3 > 2 && 2 > 1;
// true を返す

3 > 2 > 1;
// 結果は false となる。3 > 2 は true であり、true は
// 不等号で 1 に変換されるため、true > 1 は 1 > 1 となり、
// false となる。(3 > 2) > 1 のように括弧を付けると明確になる。
```

一覧表
---

以下の表は優先順位の最も高いもの (19) から最も低いもの (1) の順に並べられています。

なお、スプレッド構文はこの表から除外しています。 — 理由は Stack Overflow の回答を引用します。「スプレッド構文は演算子ではなく、優先度はありません。これは配列リテラルと関数呼び出し（およびオブジェクトリテラル）の構文の一部です。」

| 優先順位 | 演算子の種類 | 結合性 | 演算子 |
| --- | --- | --- | --- |
| 19 | グループ化 | なし | `( … )` |
| 18 | メンバーへのアクセス | 左から右 | `… . …` |
| 計算値によるメンバーへのアクセス | 左から右 | `… [ … ]` |
| `new` (引数リスト付き) | なし | `new … ( … )` |
| 関数呼び出し | 左から右 | `… ( … )` |
| オプショナルチェーン | 左から右 | `?.` |
| 17 | `new` (引数リストなし) | 右から左 | `new …` |
| 16 | 後置インクリメント | なし | `… ++` |
| 後置デクリメント | `… --` |
| 15 | 論理 NOT (!) | 右から左 | `! …` |
| ビット単位 NOT (~) | `~ …` |
| 単項 + | `+ …` |
| 単項 - | `- …` |
| 前置インクリメント | `++ …` |
| 前置デクリメント | `-- …` |
| `typeof` | `typeof …` |
| `void` | `void …` |
| `delete` | `delete …` |
| `await` | `await …` |
| 14 | べき乗 (\*\*) | 右から左 | `… ** …` |
| 13 | 乗算 (\*) | 左から右 | `… * …` |
| 除算 (/) | `… / …` |
| 剰余 (%) | `… % …` |
| 12 | 加算 (+) | 左から右 | `… + …` |
| 減算(-) | `… - …` |
| 11 | 左ビットシフト (<<) | 左から右 | `… << …` |
| 右ビットシフト | `… >> …` |
| 符号なし右ビットシフト (>>>) | `… >>> …` |
| 10 | 小なり (<) | 左から右 | `… < …` |
| 小なりイコール (<=) | `… <= …` |
| 大なり (>) | `… > …` |
| 大なりイコール (>=) | `… >= …` |
| `in` | `… in …` |
| `instanceof` | `… instanceof …` |
| 9 | 等価 (==) | 左から右 | `… == …` |
| 不等価 (!=) | `… != …` |
| 厳密等価 (===) | `… === …` |
| 厳密不等価 (!==) | `… !== …` |
| 8 | ビット単位 AND (&) | 左から右 | `… & …` |
| 7 | ビット単位 XOR (^) | 左から右 | `… ^ …` |
| 6 | ビット単位 OR (|) | 左から右 | `… | …` |
| 5 | 論理 AND (&&) | 左から右 | `… && …` |
| 4 | 論理 OR (||) | 左から右 | `… || …` |
| Null 合体 (??) | 左から右 | `… ?? …` |
| 3 | 条件（三項）演算子 | 右から左 | `… ? … : …` |
| 2 | 代入 | 右から左 | `… = …` |
| `… += …` |
| `… -= …` |
| `… **= …` |
| `… *= …` |
| `… /= …` |
| `… %= …` |
| `… <<= …` |
| `… >>= …` |
| `… >>>= …` |
| `… &= …` |
| `… ^= …` |
| `… |= …` |
| `… &&= …` |
| `… ||= …` |
| `… ??= …` |
| `yield` | 右から左 | `yield …` |
| `yield*` | `yield* …` |
| 1 | カンマ / シーケンス | 左から右 | `… , …` |