おきがるみがる

お気軽&身軽にスナップ写真を楽しむ雑記ブログです。はてなブログテーマ Sentenceの配布も行っております。

JavaScriptで使える演算子 -『JavaScript本格入門』第2章

改訂新版JavaScript本格入門 ~モダンスタイルによる基礎から現場での応用まで

改訂新版JavaScript本格入門 ~モダンスタイルによる基礎から現場での応用まで

『改訂新版JavaScript本格入門』で演算子を学びます。

演算子(オペレーター)は与えられた変数やリテラルに対して処理を行うための記号です。演算子によって処理される変数やリテラルのことをオペランドと呼びます。

値を足したり引いたり、変数に値を代入したりするための知識です。プログラミングにおいてかなり基礎的な単元です。

※前回はこちら

www.okigaru-migaru.net

算術演算子

一般的な四則計算にも使う+、-、*、/の他に以下のようなものもあります。

  • %:数値の剰余
  • ++:前置加算・後置加算
  • –:前置減算・後置減算

インクリメント演算子(++)とデクリメント演算子(–)

インクリメント/デクリメント演算子はオペランドに対して1を加算/減算します。

インクリメント/デクリメント演算子をオペランドの前後いずれかに置くかで結果が異なります。

var x = 3;
var y = x++;
console.log(x);  // 結果:4
console.log(y);  // 結果:3

var x = 3;
var y = ++x;
console.log(x);  // 結果:4
console.log(y);  // 結果:4

上の例では後置加算を行っており、xの値をyに代入してからxに1を加算します。

下の例では後置加算を行っており、xの値に1を加算してからyに代入しています。

小数点を含む計算

小数点は10進数であれば簡単に表すことができますが、2進数ではそうはいきません。

console.log(0.2 * 3);  // 結果:0.6000000000000001

例えば0.2も2進数では0.00110011…と無限循環小数となり、演算によっては正しい結果を得られない可能性があります。

console.log(((0.2 * 10) * 3) / 10);  //結果0.6

このように一度整数に戻してから計算、小数点数に戻るという方法が有効です。

小数点以下2桁までを保証する例

0.2351という小数で小数点以下2桁までを保証する場合は、

  1. 100倍して23.51としたものを演算する
  2. 最終的な結果を小数点以下で四捨五入する
  3. 2の結果を100で除算して、再び小数点数に戻す

というプロセスをとります。

代入演算子

プログラミングにおける「=」は、左辺と右辺が等しいではなく、左辺の変数に右辺の値を代入するという意味で使うことが多いです。

代入演算子は「=」以外にも以下のようなものがあります。

+=:左辺の値に右辺の値を加算したものを代入
&=:左辺の値を右辺の値で論理積演算した結果を代入
|=:左辺の値を右辺の値で論理和演算した結果を代入
^=:左辺の値を右辺の値で排他的論理和演算した結果を代入
<<=:左辺の値を右辺の値だけ左シフトした結果を代入
>>=:左辺の値を右辺の値だけ右シフトした結果を代入

定数は再代入できない

定数は再代入できませんが、配列の内容を書き換えることは可能です。

const data = [1, 2, 3];
data = [4, 5, 6]; …①
data[1] = 10; …②

①の場合は配列そのものを再代入しているので、const命令の規約違反になります。

しかし、②の場合は内容だけを書き換えているのでconst違反にはなりません。

分割代入(配列)

var data = [56, 40, 26, 82, 19, 73, 99];
var x0 = data[0];
var x1 = data[1];
var x2 = data[2];
...要素の個数だけ列挙...

と配列の各要素を個別に取り出すには、個々の要素にアクセスする必要がありました。

let data = [56, 40, 26, 82, 17, 73, 99];
let [x0, x1, x3, x4, x5, x6, x7] = data

ES2015ではこのように1行にまとめて記述することができます。

分割代入(オブジェクト)

オブジェクトのプロパティを変数に分解することもできます。

let book = { title: 'Javaポケットリファレンス', publish: '技術評論社', price: 2680 };
let { price, title, memo = 'なし' } = book;

オブジェクトの場合は配列と異なり、名前でプロパティを個々の変数に分解します。

変数の並び順はプロパティの定義準と違っていても、分解しないプロパティがあっても構いません。

比較演算子

  • ==:左辺と右辺の値が等しい場合はtrue
  • !=:左辺と右辺の値が等しくない場合はtrue
  • ===:左辺と右辺の値が等しくてデータ型も同じ場合はtrue
  • !==:左辺と右辺の値が等しくない場合、またはデータ型が異なる場合はtrue
  • ?::「条件式?式1:式2」。条件式がtrueの場合は式1を、falseの場合は式2を返す

条件演算子

var x = 80;
console.log((x >= 70) ? '合格' : '不合格');  // 結果:合格

if命令を使って同じことはできますが、単に出力する値を条件に応じて振り分けたいという場合は条件演算子を利用した方がシンプルです。

論理演算子

複数の条件式を論理的に結合し、その結果をtrue/falseとして返します。

通常は比較演算子と組み合わせて利用することで、より複雑な条件式を表現できます。

  • &&:左右の式がともにtrueの場合はtrue(AND)
  • ||:左右の式のどちらかがtrueの場合はtrue(OR)
  • !:式がfalseの場合はtrue(NOT)

ショートカット演算の注意

例えば&&演算子の場合、左式がfalseと評価された条件式全体はfalseとなって右式は評価されません。

このような演算のことをショートカット演算、あるいは短絡演算といいます。

そういうこともあって、論理演算子の後方には関数の呼び出し、インクリメント/デクリメント演算子、代入演算子など、値を実際に操作するような式を含めるべきでありません。

ビット演算子

整数値を2進数で表した場合の各桁に対して(ビット単位に)、論理計算を行う演算のことをいいます。

最初のうちはあまり利用する機会がないので、読み飛ばしてもOKとのことです。

&:左式と右式の両方にセットされているビット
|:左式と右式のどちらかにセットされているビット
^:左式と右式のどちらかにセットされていて、且つ両方にセットされていないビット
~:ビットを反転
<<:ビットを左にシフト
>>:ビットを右にシフト
>>>:ビットを右にシフト、且つ左端を0で埋める

その他の演算子

  • ,(カンマ):左右の式を続けて実行
  • delete:オブジェクトのプロパティや配列の要素を削除
  • instanceof:オブジェクトが指定されたクラスのインスタンスかを判定
  • new:新しいインスタンスを生成
  • typeof:オペランドのデータ型を取得
  • void:未定義値を返す

delete演算子

var ary = ['JavaScript', 'Ajax', 'ASP.NET']
console.log(delete ary[0]);
console.log(ary);    //結果:[1: "Ajax", 2: "ASP.NET"]

delete演算子で注意すべきは以下の3つです。

  1. 配列の要素を削除した場合、後ろの要素はくり上がらない(インデックス番号は変わらない)
  2. プロパティを削除した場合、プロパティが参照するオブジェクトが削除されるわけではない
  3. 明示的に宣言された変数を削除することはできない

typeof演算子

var num = 1;
console.log(typeof num);    //結果:number

var ary = ['JavaScript', 'Ajax', 'ASP.NET']
console.log(typeof ary);    //結果:object

typeof演算子では、文字列、数値、真偽型のような基本データ型を式別できる一方で、配列やオブジェクトはいずれも「object」と返されます。

演算子の優先順位と結合則

演算子には優先順位と、左右どちらの方向から処理するかの結合則というルールがあります。

全部覚えるのは大変なので簡単にまとめると、

  • ()でくくった部分が最優先
  • 代入演算子や単項/三項演算子が右から左への結合則