2.10 演算の優先順位、コメント

(1/1)
両手の上にJavaScriptの演算子を浮かべる陽奈
JavaScriptの演算子
AI生成コンテンツ / AI-generated content
JavaScriptの式の評価は、算数で習ったように、乗除算は加減算より優先して実行される。各種演算の優先順位を一覧表にした。プログラムに説明を加えたり、一部のプログラムを実行させないようにするために、コメント機能を備えている。
(2026年9月18日)演算子の優先順位、結合性、コメント、strict mode、言語処理系の説明を訂正。練習問題とサンプル・プログラムを修正し、キーイラストを差し替えた。

目次

演算の優先順位

JavaScriptの式の評価は、算数で習ったように、乗除算は加減算より優先して実行される。 $ 1+2 \times 3 $ の解は9ではなく7だ。
これまで紹介してきた演算子の優先順位には、算数・数学で習った規則と共通するものも多い。ここで、主な優先順位を一覧にしておこう。
取り上げるプログラムは、これまでダウンロードしたものである。
主な演算子の優先順位(数が大きいほど先にまとまる)
順位演算子演算
18(...)グループ化
17… . …メンバへのアクセス
… [ … ]計算値によるメンバへのアクセス
new … ( … )new (引数リスト付き)
… ( … )関数呼び出し
?.オプショナルチェーン
16new …new (引数リストなし)
15... ++後置インクリメント
... --後置デクリメント
14! ...論理否定
~ ...ビット否定
+ ...単項 +
- ...単項 -
++ ...前置インクリメント
-- ...前置デクリメント
typeof ...typeof
void ...void
delete ...delete
awaitawait
13**べき乗
12*乗算
/除算
%剰余算
11+加算
-減算
10<<左ビットシフト
>>右ビットシフト
>>>符号無し右ビットシフト
9<小なり
<=以下
>大なり
>=以上
inin
instanceofinstanceof
8==等価
!=不等価
===厳密等価
!==厳密不等価
7&ビット論理積
6^ビット排他的論理和
5|ビット論理和
4&&論理積
3||論理和
??Null合体
2... ? ... : ...条件(三項)演算
2=
+=
-=
**=
*=
/=
%=
<<=
>>=
>>>=
&=
^=
|=
&&=
||=
??=
代入演算
yieldyield
yield*yield*
1,カンマ

div1.html

  10: let a = 1, b = 2;
  11: let c = a / b;

comp4.html

  26:     if ((year >= 1980) && (year <= 1989)) {
  27:         result = 'です';
  28:     } else {

演算の優先順位が曖昧なときは、グループ (...) で囲って明示した方がいい。

セミコロン ; は文の区切りに使う。JavaScriptには、一定の条件でセミコロンを補う自動セミコロン挿入(ASI)があるが、改行した場所で必ず文が終わるわけではない。意図しない解釈を避けるため、本編では文末にセミコロンを書く。

コメント

JavaScriptでは、プログラムに説明を加えたり、一部のコードを一時的に実行対象から外したりするために、コメントを記述できる。

1行コメント // は、// から行末までをコメントとして扱う。

increment1.html

  20: //ページのロード時に実行
  21: window.onload = function() {

logic1.html

  22:     const a = true;
  23:     const b = false;

複数行コメント /* ... */ は、/* から */ までをコメントとして扱う。1行だけにも複数行にも使える。複数行コメントは入れ子にできず、最初の */ で終了する。

bit1.html

  19: <script>
  20: /**
  21:  * 計算と画面表示
  22: */
  23: function execute() {

コラム:オペランドと結合性

演算子の対象になる値や式をオペランドと呼ぶ。
たとえば $$ 1 + 2 $$ では、演算子は $ + $(加算)で、オペランドは $ 1 $ と $ 2 $ である。
$$ 2 * x $$ では、演算子は $ * $(乗算)で、オペランドは $ 2 $ と $ x $ である。

次に、優先順位が同じ演算子をどのようにまとめるかを見ておこう。$$ 1 + 2 + 4 $$ の加算演算子 $ + $ は左結合なので、$$ (1 + 2) + 4 $$ とまとめられ、結果は $ 7 $ になる。このまとめ方を結合性という。
ただし、結合性はオペランドそのものを読み出す順序とは異なる。また、論理積 && や論理和 | などでは、左側の値だけで結果が決まると右側を評価しない短絡評価が行われる。
主な演算子の優先順位と結合性
順位演算子演算結合性
18(...)グループ化なし
17… . …メンバへのアクセス左から右
… [ … ]計算値によるメンバへのアクセス左から右
new … ( … )new (引数リスト付き)なし
… ( … )関数呼び出し左から右
?.オプショナルチェーン
16new …new (引数リストなし)なし
15... ++後置インクリメントなし
... --後置デクリメントなし
14! ...論理否定右から左
~ ...ビット否定
+ ...単項 +
- ...単項 -
++ ...前置インクリメント
-- ...前置デクリメント
typeof ...typeof
void ...void
delete ...delete
awaitawait
13**べき乗右から左
12*乗算左から右
/除算
%剰余算
11+加算左から右
-減算
10<<左ビットシフト左から右
>>右ビットシフト
>>>符号無し右ビットシフト
9<小なり左から右
<=以下
>大なり
>=以上
inin
instanceofinstanceof
8==等価左から右
!=不等価
===厳密等価
!==厳密不等価
7&ビット論理積左から右
6^ビット排他的論理和左から右
5|ビット論理和左から右
4&&論理積左から右
3||論理和左から右
??Null合体左から右
2... ? ... : ...条件(三項)演算右から左
2=
+=
-=
**=
*=
/=
%=
<<=
>>=
>>>=
&=
^=
|=
&&=
||=
??=
代入演算右から左
yieldyield右から左
yield*yield*右から左
1,カンマ左から右
演算子を含む式を評価すると、値が得られる。前述の例では、$ 1 + 2 $ の値 $ 3 $ が次の加算のオペランドになり、$ 3 + 4 $ を計算する。
代入演算子 $ = $ は、右辺の値を左辺へ代入し、代入した値を式全体の値として返す。したがって、$$ x = 1 + 2 + 4 $$ では $ 7 $ が $ x $ に代入される。また、$$ y = x = 1 + 2 + 4 $$ は右から $$ y = (x = 7) $$ とまとめられ、$ x $ と $ y $ の両方に $ 7 $ が代入される。

練習問題:演算の優先順位

コラム:strict mode

「コラム:JavaScript,Java,ECMA Script - 1.2 画面にメッセージを表示する」で紹介したように、JavaScriptはブラウザ用の簡易スクリプトとして誕生したのだが、その後、プログラミング言語としての体裁を整え、ES2015(ES6) からは大規模なシステム開発もできるようになった。
ところが、大規模なシステム開発を行うのに、旧来の言語仕様に好ましくないものが幾つも出てきた。そこで、2009年(平成21年)12月に公開された ES5 では、strict mode (ストリクト モード)  というモードを設け、好ましくない仕様で書いたプログラムは実行時にエラーを出すようにした。

たとえば、"strict1.html" を実行してみてほしい。

strict1.html

  20: <script>
  21: //ページのロード時に実行
  22: window.onload = function() {
  23:     a = 1;
  24:     document.getElementById('let1').textContent = a.toString();
  25: }
  26: </script>

ここで、変数 a は暗黙のグローバル変数となる。
しかし、大規模なシステム開発において安易にグローバル変数が宣言できてしまうのは好ましくない。

JavaScriptの冒頭に "use strict"; と1行記述すると、そのスクリプトは strict mode になる。関数の本体の冒頭に書けば、その関数だけに適用できる。
"strict2.html" を実行してみてほしい。画面には何も表示しなくなるが、コンソールを見るとエラーが出ているのが分かる。

strict2.html

  20: <script>
  21: "use strict";       // strict mode
  22: 
  23: //ページのロード時に実行
  24: window.onload = function() {
  25:     a = 1;          // エラーになる
  26:     document.getElementById('let1').textContent = a.toString();
  27: }
  28: </script>

strict mode では、このほかにも、通常モードなら見逃される操作がエラーになったり、動作が変わったりする。

■書き換え不可なプロパティへの代入
"use strict";
var obj = {};
Object.defineProperty(obj, "x", { value: 1, writable: false });
obj.x = 2;    // ❌ TypeError: Cannot assign to read only property 'x'
■getter しかないプロパティへの代入
"use strict";
var obj = {
    get x() { return 10; }
};
obj.x = 20;    // ❌ TypeError
■delete の禁止対象を削除
"use strict";
delete Object.prototype;    // ❌ TypeError
■ 重複する引数名
"use strict";
function f(x, x) {    // ❌ SyntaxError
    return x;
}
■ 8進数リテラル
"use strict";
var x = 010;    // ❌ SyntaxError (先頭0の数値リテラル禁止)
■ with 文の禁止
"use strict";
var obj = {a: 1};
with (obj) {    // ❌ SyntaxError
    console.log(a);
}
■ 関数内のthisが自動でグローバルオブジェクトを指さなくなる
"use strict";
function f() {
    console.log(this);    // undefined(通常のブラウザースクリプトではwindow)
}
f();
本編では、できる限り strict mode でも問題なく動くプログラムを紹介しているが、サンプルを短くするため "use strict"; は明示していない。
なお、JavaScriptモジュール(ESモジュール)は、指定しなくても常に strict mode で実行される。

コラム:アセンブラ、コンパイラ、インタプリタ

はじめて読む8086
コンピュータの演算や制御を担う装置が CPU(中央演算処理装置)である。インテルの Core i シリーズや、アップルの Apple M1 などがCPUである。

CPUが直接理解できる命令群(プログラム)のことを機械語(マシン語)と呼ぶ。これはバイナリデータであり、CPUの種類によって変わるため、人間が見ても解読するのは難しい。
Personal CP/M
機械語の命令を、人間が読みやすい英単語や略号に対応させたものがアセンブリ言語である。CPUごとに命令体系が異なるため、そのCPUの知識が必要になる。アセンブリ言語で書かれたプログラムは、アセンブラによって機械語へ変換され、CPUが実行する。
Microsoft FORTRAN
1950年代後半には、FORTRAN、LISP、COBOL など、人間がアルゴリズムを表しやすい高水準言語が相次いで登場した。同じソースコードでも、CPUやOSに対応した処理系を使うことで別の環境向けに変換できる。これに対し、機械語に近いアセンブリ言語は低水準言語と呼ばれる。「高水準」は、人間の考え方に近い抽象度を表す言葉で、価格の意味ではない。
Small-Cコンパイラ
高水準言語の処理方法には、実行前にプログラム全体を別の形式へ変換するコンパイラと、実行しながら命令を処理するインタプリタがある。コンパイラが直接機械語を生成する場合もあれば、中間表現やアセンブリ言語を経由する場合もある。

現代のJavaScriptエンジンは、インタプリタだけで動くとは限らない。たとえばV8は、ソースコードをバイトコードへ変換して実行し、繰り返し使われる部分をJIT(実行時)コンパイラで最適化された機械語へ変換する。JavaScriptという言語の仕様と、処理系が採用する実行方式は分けて考える必要がある。
PHP 8
一般に、事前に機械語へ変換したプログラムは高速に実行しやすいが、起動時間や最適化の方法なども性能に影響する。現在は、インタプリタ、事前コンパイル、JITコンパイルを組み合わせる処理系が多く、単純に二分することは難しい。PHP 8にもJITによる高速化の仕組みがある。

参考サイト

(この項おわり)
header