演算子の優先順位
演算子の優先順位 とは
*が+より先、&&が||より先、というルールを意識して、意図通りの式を書けるようになろう。
演算子の優先順位を意識する
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 && c は a || (b && c) の意味になります。「a または、b かつ c」という日本語に対応します。
Mermaid で評価順を追う
1 + 2 * 3 の評価順を図にすると次のとおりです。
図を見ると、優先順位が高い * を先に評価して、後から + を処理する流れがよく分かります。
結合性 (左結合 / 右結合)
同じ優先順位の演算子が並んだとき、左右どちらから評価するかを決めるのが 結合性 です。
- 左結合 —
+-*/%<>===&&||?? - 右結合 —
**=?:
左結合の例は 10 - 3 - 2 です。(10 - 3) - 2 = 5 と左から評価されます。
右結合の代表は代入の = です。a = b = c = 5; は a = (b = (c = 5)); と右から評価され、3 つの変数が 5 になります。** も右結合で、2 ** 3 ** 2 は 2 ** (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)はxに5を代入してから真偽値を評価するので、いつもtrueになる無限ループのもとです。比較は===、代入は=と意識を分けてください !を後置と勘違い —!は 前置。x !ではなく!xと書きます。a == !bとa !== bも別物なので注意
もうひとつ、+ と ++ の組み合わせも危険です。
JavaScript
let x = 5;
console.log(x++ + ++x); // 12x++ は「先に値を返してから 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 つができることを確認しましょう。
- 優先順位 の要点を自分の言葉で説明できる
- このレッスンの最小コード (または操作手順) を見ずに書ける
- 練習問題やクイズで間違えた箇所を読み直して理解した
理解度チェック (30 秒)
Q. 優先順位 とは何か、1 文で説明してください。
A. 本文の「このレッスンで分かること」または冒頭の説明文を見直し、自分の言葉で要約できれば OK。詰まったら本レッスンの最初の H2 セクションを読み返してみましょう。
関連レッスン
要件
- 関数名は
compute、引数はabcの 3 つにすること - 式
a + b * c - (a + b) * 2をそのままreturnで返すこと (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