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

(1/1)
コメント
JavaScriptの式の評価は、算数で習ったように、乗除算は加減算より優先して実行される。各種演算の優先順位を一覧表にした。プログラムに説明を加えたり、一部のプログラムを実行させないようにするために、コメント機能を備えている。
(2025年8月27日)記事「コラム:strict mode」,サンプル・プログラムを追記した.
(2025年8月22日)記事「コラム:オペランドと結合性」追記

目次

演算の優先順位

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

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

JavaScriptでは、セミコロン ; までが1つの式として評価される。途中で改行しても連続した式と認識される。長い式は、途中で改行した方が読みやすいだろう。

コメント

JavaScriptでは、プログラムに説明を加えたり、一部のプログラムを実行させないようにするために、コメント機能を備えている。

1行コメント // は、これより改行までをコメントとして実行しない。

increment1.html

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

logic1.html

  22:     let ua = navigator.userAgent.toUpperCase();     //大文字変換
  23:     let res;                                        //判定結果

複数行コメント /* ... */ は、これが囲まれた部分(1行でも複数行でもいい)をコメントとして実行しない。コメントはネストできないので、*/ が出てきた時点で、すべてのコメント終了となる。

bit1.html

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

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

演算子が影響を与えるものをオペランドと呼びます。
たとえば $$ 1 + 2 $$ であれば、演算子は $ + $(加算)で、オペランドは $ 1 $と$ 2 $ です。
$$ 2 * x $$ では、演算子は $ * $(乗算)で、オペランドは $ 2 $と $ 2 x $ です。

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

練習問題:演算の優先順

コラム:strict mode

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

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

strict1.html

  20: <script>
  21: //ページのロード時に実行
  22: window.onload = function() {
  23:     a = 1;
  24:     document.getElementById('let1').innerHTML = a;
  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').innerHTML = a;
  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 / global)
}
f();
本編では、できる限り strict mode でエラーが出ないプログラムを紹介するようにしており、"use strict;" は明示していない。
なお、本編では紹介しないが、JavaScriptモジュールでは原則として strict mode になる。厳密にいうと、ESモジュール (ESM)では必ず strict mode になるが、それ以外のモジュールは強制ではないが、実装によっては strict mode になる。

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

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

CPUが直接理解できる命令群(プログラム)のことを機械語(マシン語)と呼ぶ。これはバイナリデータであり、CPUの種類によって変わるため、人間が見ても解読するのは難しい。
Personal CP/M
機械語の命令を、それに近い英単語(または略号)に置き換えたものがアセンブリ言語と呼ばれるプログラミング言語である。人間が読むことはできるが、CPUの種類によって変わることは同じで、そのCPUの命令体系を熟知していないと理解は難しい。アセンブラ言語で書かれたプログラムは、アセンブラを介して機械語に翻訳され、CPUが直接実行できた。
Microsoft FORTRAN
1950年代後半、CPUによる差異を無くし、人間が読みやすいように(作りやすいように)作られた FORTRANCOBOLLISP といったプログラミング言語が登場した。これらは高級言語(高水準言語)と呼ばれ、アセンブラは低級言語(低水準言語)として区別された。高級というのは「高価」という意味ではなく、人間が読める水準にあるという意味だった(高級言語の開発環境は高価ではあったが‥‥)。
Small-Cコンパイラ
当時の高級言語は、コンパイラという仕組みを介して、各々のCPUに合ったアセンブラ言語に翻訳され、最終的にCPUが直接実行できる機械語にしてから実行するというものだった。

JavaScriptは、CPUに依存しないが、コンパイラを介してプログラムを実行しているわけではない。ファイルやメモリからプログラムを逐次読み出ししてCPUに実行させている。このような仕組みをインタプリタと呼ぶ。
PHP 8
かつては、コンパイラで作られたプログラムはインタプリタより実行速度が速かったのだが、最近のコンパイラは純粋なアセンブリ言語に翻訳しなかったり、逆にインタプリタでもコンパイル機能を備えたものが登場(PHP 8:JITによる高速化)したことなどにより、両者の境界は曖昧になっている。
(この項おわり)
header