演算子の優先順位

生田 陸人
LuaGate エンジニア / 現役エンジニア
編集 LuaGate編集部

演算子の優先順位 とは

*+ より先、&&|| より先、というルールを意識して、意図通りの式を書けるようになろう。

演算子の優先順位を意識する

JavaScript には数十種類の演算子があり、それぞれに 優先順位 が決まっています。たとえば 1 + 2 * 3 の答えが 7 (9 じゃない) になるのは、* のほうが + より先に評価されるという小学校で習ったルールが効いているからです。

この優先順位を意識しないままコードを書くと、たまにとんでもないバグを生みます。一方で、優先順位を完璧に暗記する必要はありません。よく使う組み合わせだけ覚え、迷ったら () を使う のが現代の現場のスタンスです。

優先順位の暗記より大事なのは、「あれ、これどっちが先だっけ?」と思った瞬間に () を書ける習慣です。読み手にとっても親切です。

よく使う優先順位 (高い順)

上から優先順位が高い順に並べた、頻出の演算子は次のとおりです。

  • () グルーピング — 一番強い
  • ! 単項否定、++ -- インクリメント / デクリメント
  • ** べき乗
  • * / % 乗除剰余
  • + - 加減
  • < <= > >= 比較
  • === !== == != 等価
  • && 論理 AND
  • || ?? 論理 OR / nullish 合体
  • ?: 三項演算子
  • = += -= 代入 — 一番弱い

大ざっぱには「算数 → 比較 → 論理 → 三項 → 代入」の順だと覚えると、9 割の式は迷いません。

よくある式の例

実際にどう評価されるか、いくつか見てみます。

JavaScript

console.log(1 + 2 * 3); // 7 乗算が先 console.log((1 + 2) * 3); // 9 カッコで足し算を先に console.log(10 - 3 - 2); // 5 同じ優先順位は左から (左結合) console.log(2 ** 3 ** 2); // 512 べき乗は右結合 2 ** (3 ** 2) console.log(1 + 2 === 3); // true (1 + 2) === 3 console.log(true || false && false); // true || (false && false) = true

最後の ||&& の例は要注意です。&& のほうが || より優先順位が高い ので、a || b && ca || (b && c) の意味になります。「a または、b かつ c」という日本語に対応します。

Mermaid で評価順を追う

1 + 2 * 3 の評価順を図にすると次のとおりです。

diagram (will load when visible)

図を見ると、優先順位が高い * を先に評価して、後から + を処理する流れがよく分かります。

結合性 (左結合 / 右結合)

同じ優先順位の演算子が並んだとき、左右どちらから評価するかを決めるのが 結合性 です。

  • 左結合 — + - * / % < > === && || ??
  • 右結合 — ** = ?:

左結合の例は 10 - 3 - 2 です。(10 - 3) - 2 = 5 と左から評価されます。

右結合の代表は代入の = です。a = b = c = 5;a = (b = (c = 5)); と右から評価され、3 つの変数が 5 になります。** も右結合で、2 ** 3 ** 22 ** (3 ** 2) = 2 ** 9 = 512 です。意外な落とし穴です。

結合性まで頭に入れる必要は普段ありません。「あれ?」と思ったら () で書き直すだけで全部解決します。

() をつけるべき場面の典型例

次のようなパターンでは、たとえ優先順位が分かっていても () を付けたほうが読みやすいです。

JavaScript

// 比較と論理を混ぜるとき const ok = (age >= 18) && (isMember || isInvited); // 三項演算子と算術を混ぜるとき const total = base + (isVip ? bonus * 2 : bonus); // ?? と || を混ぜるとき (構文エラー回避) const v = (a || b) ?? c;

最後の例は 構文エラーを避けるためにカッコが必須 です。||?? は混ぜると JavaScript の文法的に許されないので、必ずどちらかを () で囲みます。

よくある間違い

優先順位まわりの落とし穴を 3 つ。

  • + と文字列連結の優先順位"合計: " + 1 + 2"合計: 12" になります。"合計: " + (1 + 2) と書かないと 3 にはなりません。文字列連結は 左から評価 されて、最初の + の時点で文字列モードに突入します
  • 代入は一番弱いif (x = 5)x5 を代入してから真偽値を評価するので、いつも true になる無限ループのもとです。比較は ===、代入は = と意識を分けてください
  • ! を後置と勘違い!前置x ! ではなく !x と書きます。a == !ba !== b も別物なので注意

もうひとつ、+++ の組み合わせも危険です。

JavaScript

let x = 5; console.log(x++ + ++x); // 12

x++ は「先に値を返してから 1 増やす」、++x は「先に 1 増やしてから値を返す」。可読性の面からも、+++ と組み合わせるのは避けるべきです。

「カッコは負けの印じゃない、むしろ勝利の印」。読みやすさのために () を惜しまない、これがプロのコードです。

やってみよう

それでは課題に取り組みましょう。compute(a, b, c) を完成させて、次の式の結果を返してください。

a + b * c - (a + b) * 2

書き方の方針は次のとおりです。

  • そのまま JS の式に置き換える
  • b * c の部分は + より先に評価されることを意識
  • 後半は (a + b)() で囲んで足し算を先にし、その結果を 2
  • 全体としては a + (b * c) - ((a + b) * 2) という意味

短い課題ですが、() の役割と優先順位の感覚を体に染み込ませる練習です。式が複雑になっても、() を使い慣れていれば落ち着いて読み解けるようになります。

よくある質問

Q. ブラウザと Node.js で動作は変わりますか?

A. JavaScript の構文・組み込み機能(配列・文字列・Promise 等)はどちらでも同じです。違いは DOM API(ブラウザ専用)と fs などのファイル系(Node 専用)など、実行環境固有の機能です。コアロジックは両方で動くため、テストもしやすくなります。

Q. ES6 以降の新機能は使っても大丈夫ですか?

A. 現代のブラウザ・Node.js は ES2020 以降の機能をほぼサポートしています。古い IE 等を対象にする必要が無ければ、let/const、アロー関数、分割代入、async/await を積極的に使ってください。トランスパイル(Babel/Vite)が必要なケースは年々減っています。

Q. TypeScript に進む価値はありますか?

A. 型情報があるとリファクタやエディタ補完が劇的に効くため、規模が大きくなるなら TypeScript への移行を強くおすすめします。最初は any を許容しつつ徐々に型を付ければ、JS の知識をそのまま活かせます。

次のレッスン

次は 第3章まとめクイズ で、*+ より先、&&|| より先、というルールを意識して、意図通りの式を書けるようになろう を学びます。

事前確認 — 進む前に次の 3 つができることを確認しましょう。

  1. 優先順位 の要点を自分の言葉で説明できる
  2. このレッスンの最小コード (または操作手順) を見ずに書ける
  3. 練習問題やクイズで間違えた箇所を読み直して理解した

理解度チェック (30 秒)

Q. 優先順位 とは何か、1 文で説明してください。

この章のポイント

A. 本文の「このレッスンで分かること」または冒頭の説明文を見直し、自分の言葉で要約できれば OK。詰まったら本レッスンの最初の H2 セクションを読み返してみましょう。

関連レッスン

要件

  1. 関数名は compute、引数は a b c の 3 つにすること
  2. a + b * c - (a + b) * 2 をそのまま return で返すこと
  3. (a + b) の部分はカッコで囲んで足し算を先に評価すること

入出力例

test-cases.txt

compute(1, 2, 3)1 compute(0, 0, 0)0 compute(2, 3, 4)4 compute(5, 0, 10)-5 compute(-1, 2, 3)3

ヒント

main.js
main.js
学習モード

メモ

演算子の優先順位

⌘S で保存