演算子①:基本の演算子

Loading

プログラミングをする上で必ず出会うのが演算子です。
演算子は数式の計算や文字列の処理など、あらゆる処理に欠かせない要素になります。

今回は基本的な演算子の使い方を学んでいきましょう。

目次

演算子とは?

何らかの値をもとに処理を行うことを演算と呼びます。その演算を行うための記号を演算子と呼びます。
例えばたし算「+」やかけ算「×」は2つの数値をもとに1つの数値を計算する演算子です。

また、演算子によって処理される値をオペランドと言います。

例えば「1 + 2」であれば、「+」が演算子、「1」や「2」がオペランドになります。

演算子には下記のような種類があります(全てではありません)。

演算子説明
算術演算子数値を使用した計算をします
関係演算子値の比較を行います
等価演算子値が等しいかどうかを判定します
論理演算子論理演算をします
ビットシフト演算子ビット計算を行います
代入演算子変数へ値を代入します
単項演算子一つのオペランドに対して演算子の処理を行います
三項演算子条件に則って、2つの値のいずれかを返却します
カンマ演算子複数の演算対象を評価し、最後のオペランドを返します
Null合体演算子左のオペランドがnullまたはundefinedの場合に右のオペランドを返却します
オプショナルチェイニング演算子オブジェクト以外の値に対してプロパティを取得した場合にundefinedを返します
スプレッド演算子配列を展開します
演算子の一覧

演算子の優先順位

演算子には優先順位というものがあります。
例えば次のような変数への代入を考えましょう。

let a = 1 + 2;

この場合、「=」は変数に値を代入する演算子です。代入演算子といいます。
上記の式には2つの演算子「=」「+」が出てきますが、これらはどんな順番で値を処理するでしょうか。

答えは、「+」が最初に処理され、後で「=」が処理されます。

  1. 1 + 2が先に計算され、3となる
  2. この3という結果が変数aに代入される

このように、演算子には適用される順番に優先度が設定されています。
優先度の高い演算子ほど先に処理されます。
上記の例では、「+」が優先度が高く先に処理され、その後に優先度の低い「=」が実行されます。

優先度が高い順から並べると、おおむね下記のような優先度になります(数値が小さいほど優先度が高くなります)。

  1. 単項演算子
  2. 算術演算子
  3. ビットシフト演算子
  4. 関係演算子
  5. 等価演算子
  6. 論理演算子
  7. 代入演算子

算術演算子

数値計算に使われる演算子を算術演算子と呼びます。

演算子用途結果
+加算1 + 23
減算14 – 212
*乗算7 * 321
/除算27 / 93
%剰余11 % 32
**べき乗2 ** 38
++1を加算let x = 2;
x++;
3
1を減算let y = 7;
y–;
6
算術演算子のリスト

ここで、インクリメント演算子「++」とデクリメント演算子「–」は本来、単項演算子(オペランドが1つの演算子)に分類されますが、数値計算と関連が深いためここで紹介します。

インクリメント演算子

インクリメント演算子「++」は、変数の値を1だけ増やす演算子です。

let x = 1;
x++;

console.log(x);
> 2

インクリメント演算子は次の式と同じ結果になります。

let x = 1;
x = x + 1; // x + 1 が先に計算され、xに再代入される

console.log(x);
> 2

ここで、「x = x + 1」という書き方に引っかかった方も多いのではないかと思います。
ここで、「=」は数学的なイコールではなく、代入演算子であることに注意しましょう。
やっていることは「a = 1 + 2」と変わりません。

  1. 「+」が優先度が高いため、先に「x + 1」が計算され、2という結果になる
  2. 「=」によって2という結果がxに代入される

また、インクリメント演算子には「前置」と「後置」の概念があります。
「++」を変数の前に置くと前置、変数の後に置くと後置になります。

let x = 1;
let y = 1;

let a = ++x; // 前置インクリメント
let b = y++; // 後置インクリメント

console.log(x);
> 2

console.log(y);
> 2

上記のコードで、xとyが「2」になることは同じです。
では、前置と後置で何が変わるでしょう?

答えは、インクリメントして返却される値にあります。
上記の変数aでは、インクリメントされた後のxの値「2」が代入されます。
また、変数bでは、インクリメントされる前のyの値「1」が代入されます。

つまり、

  • 前置インクリメントでは、インクリメント(+1)が先に実行されて、「2」が返される
  • 後置インクリメントでは、インクリメントが実行される前の「1」が返される

という違いがあります。

console.log(a);
> 2

console.log(b);
> 1

xの中身が+1されることは変わりませんが、返却される値が変わってきますので、それぞれの違いをしっかり押さえておきましょう。

デクリメント演算子

デクリメント演算子「–」は、変数の値を1だけ減らす演算子です。

let x = 1;
x--;

console.log(x);
> 0

デクリメント演算子は次の式と同じ結果になります。

let x = 1;
x = x - 1; // x - 1 が先に計算され、xに再代入される

console.log(x);
> 0

インクリメント演算子では+1が実行されますが、デクリメント演算子では-1が実行されていますね。

また、デクリメント演算子にもインクリメント演算子と同じく、前置と後置の違いがあります。

let x = 1;
let a = --x;

console.log(x);
> 0
console.log(a);
> 0

let y = 1;
let b = y--;

console.log(y);
> 0
console.log(b);
> 1

インクリメント演算子と同様に、

  • 前置デクリメントでは、デクリメント(-1)が先に実行されて、「0」が返される
  • 後置デクリメントでは、デクリメントが実行される前の「1」が返される

ということに注意しましょう。

関係演算子

2つの値を比較し、Boolean型の真偽値を返す演算子を関係演算子と呼びます。

演算子用途結果
A < BAがBより小さいことの確認1 < 2true
1 < 1false
A > BAがBより大きいことの確認2 > 1true
1 > 1false
A <= BAがB以下であることの確認1 <= 2true
1 <= 1false
A >= BAがB以上であることの確認2 >= 1true
1 >= 1false
A in BAのプロパティがBのオブジェクトのプロパティとして含まれるかの確認“val” in { val: 1}true
“noVal” in { val: 1 }false
関係演算子のリスト

関係演算子は「in」を除くと、数学的な大小比較と意味は同じですので、覚えやすいかと思います。

「<=」を誤って「=<」と逆にしてしまうとエラーになりますので注意しましょう。
「>=」に関しても同様です。
以上・以下に関しては「イコールは右にくる」と覚えておきましょう。

等価演算子

2つの値が等しいかどうかを判定しBoolean型の真偽値を返す演算子を等価演算子と呼びます。

演算子用途結果
==値が等しいことを確認1 == “1”true
1 == 1true
===値と型が等しいことを確認1 === “1”false
1 === 1true
!=値が等しくないことを確認1 != “1”false
1 != 2true
!==値と型が等しくないことを確認1 !== “1”true
1 !== 1false
等価演算子のリスト

上の表の通り、「==」は型の違いを無視して値が等しいことを確認するのに対し、「===」は型と値が厳密に等しいかどうかを確認します。

「==」は両辺で型が違う場合は、暗黙の型変換という処理で、無理やり両辺の型をあわせた上で比較が行われます。
例えば、「1 == true」という比較の場合、trueを数値に変換する、すなわち Number(true) を実行した上で値が比較されます。
Number(true)の結果は1なので、最終的にこの比較は「true」という結果が返ってきます。

この他にも、「null == undefined」という比較に関しても「true」が返る仕様となっています。

両辺の型を考えずに比較できるため一見便利そうに見えますが、この比較処理の仕様は大変複雑であり、バグの温床になりやすいリスクを孕んでいます。
基本的には「===」や「!==」などの型も含めた厳密な等価演算子を使うのが一般的です。

オブジェクト同士の比較

以上で説明したことはプリミティブ型の値の比較についてでした。
しかし、オブジェクトの比較の様子は少し異なります。

結論から言うと、オブジェクトの比較では値の比較ではなく、オブジェクトを格納しているアドレス同士の比較が行われます。

次のような比較を行ったとします。

let a = {};
let b = {};
console.log( a === b );
> false

変数a、bに格納されているオブジェクトはどちらも空のオブジェクトのため、直感的にはaとbは同じ値になると思うかもしれません。
しかし、2つのオブジェクトはそれぞれ異なるメモリに格納されており、変数aとbが参照しているアドレスは別のものになります。
等価演算子はオブジェクトが対象の場合は、メモリアドレスが同じかどうかを判定するため、aとbは異なると判定され、falseが結果として返ります。

オブジェクト同士の比較
オブジェクト同士の比較

このように、等価演算子は値がプリミティブか非プリミティブ(つまりオブジェクト)かどうかで比較するものが変わりますので、注意が必要です。

変数の値とメモリの関係については、以下の記事も参照してください。

論理演算子

2つの真偽値の論理和、論理積をとる演算子を論理演算子と呼びます。

演算子用途結果
A && BAとBの論理積(AND)を計算するtrue && truetrue
true && falsefalse
A | | BAとBの論理和(OR)を計算するtrue && falsetrue
false && falsefalse
論理演算子のリスト

論理積とは、AとBともにtrueの場合のみtrueを返す演算です。
論理和とは、AとBともにfalseの場合のみfalseを返す演算です。

論理演算子はif文やfor文などの判定式に使われます。

論理演算の短絡評価

論理演算子には短絡評価という仕組みがあります。
これは、オペランドの評価途中でもそこで演算結果が確定するならば、その後のオペランドの評価は行わないという仕様のことです。

これだけでは分かりにくいと思うので、具体的に見ていきましょう。

論理積「A && B」はAとBともにtrueの場合のみtrueを返す演算でした。
ということは、Aを評価した結果falseだった場合、その段階で「A && B」の結果はfalseであることが確定します。
そのため、Aの評価だけで(Bの評価は行わず)、falseという結果が返ります。

このように、評価が確定したらその後の処理を省略することを短絡評価と言います。

論理和についても見ていきましょう。

論理和「A || B」はAとBともにfalseの場合のみfalseを返す演算でした。
そのため、Aがtrueであれば、その時点で「A || B」の結果はtrueになることが確定します。
そのため、その時点でBの評価を省略してtrueという結果が返却されます。

まとめ

今回は基本的な演算子について、その使い方を説明しました。

次回は演算子についてさらに突っ込んで、特殊な演算子について紹介します。