こんにちは。
今回はまたJavaScript本格入門の内容のアウトプットをしようかと思います。
##等価演算子と同値演算子とは?
###等価演算子とは
等価演算子「==」は左辺と右辺の値を比較して、等しい場合にはtrue、等しくない場合にはfalseを返す演算子です。
しかし、オペランドのデータ型によって比較の基準が違ってくるので注意しましょう。
JavaScript本格入門では等価演算子を**「オペランドのデータ型が異なっていてもデータ型を変換して『なんとか等しいと見なせないか』を試みる」**と説明しています。
例えば以下のような数値と論理値の比較も等価演算子を使用するとtrueと返ってきます。
console.log(1 == true); //結果:true
また、等価演算子で特に注意が必要なのが比較の対象が配列/オブジェクト同士である場合です。
let data1 = ['JavaScript', 'Ajax', 'ASP.NET'];
let data2 = ['JavaScript', 'Ajax', 'ASP.NET'];
console.log(data1 == data2); //結果:false
上記の例のように見かけでは同じ内容の変数であっても結果はfalseが返ってきます。
これは配列/オブジェクトのような参照型の場合には変数に参照値が格納されるためです。
そのため、中身は一緒であったとしても変数に格納されているメモリ上のアドレスである参照値が異なるのでfalseを返します。
###同値演算子とは
等価演算子はデータ型を変換して判定をしてくれるので、開発者側としてはデータ型をそこまで意識することなくコーディングができます。
しかし、その便利な機能が裏目に出て以下のような問題が発生することがあります。
console.log('3.14E2' == 314);
console.log('0x10' == 16);
console.log('1' == 1);
//結果は全てtrue
3.14E2は指数表現として解釈、0x10は16進数として解釈がされてしまっています。
これでは思わぬ問題が発生しかねません。
そこで登場するのが**同値演算子「===」**です。
同値演算子はデータ型を変換しないという点を除いて等価演算子と同じ働きをします。
console.log('3.14E2' === 314);
console.log('0x10' === 16);
console.log('1' === 1);
//結果は全てfalse
JavaScriptはデータ型に寛容にできている言語ではありますが、しっかりデータ型を区別しています。
大規模なアプリ開発ではこの寛容さがバグの原因となるそうなので、値を比較する際には同値演算子を使用するよう意識した方が良いでしょう。
##条件演算子とは
これは僕は知らなかった演算子なのですが、条件演算子というものがあるそうです。
条件演算子は指定された条件式の真偽に応じて、対応する式の値を出力したい場合に使用します。
let x = 80;
console.log((x >= 70) ? '合格' : '不合格'); //結果:合格
if文を使用すれば同様の処理ができますが、出力する値を条件に応じて振り分けたいという状況であればこちらの方がシンプルにコードがかけます。
##論理演算子
論理演算子は複数の条件式、論理値を論理的に結合して、その結果をtrueもしくはfalseで返します。
・&&
左右の式がともにtrueの場合にtrueを返す。
・||
左右の式のどちらかがtrueの場合にtrueを返す。
・!
式がfalseの場合にtrueを返す。
let x = 1;
let y = 2;
console.log(x === 1 && y === 1); //結果:false
console.log(x === 1 || y === 1); //結果:true
また、以下の値はJavaScriptではfalseと処理されます。
・空文字列("")
・数値の0、NaN(Not a Number)
・null、undefined
###ショートカット演算
論理積、論理和演算子を利用する場合に気をつける必要があるのがショートカット演算です。
例えば、論理積の場合には左式がfalseと評価された時点で条件式全体が必ずfalseとなるので、右式の評価は実行されません。
これをショートカット演算と呼びます。
このショートカット演算から以下の1と2は意味的に同じになります。
if(x === 1){console.log('こんにちは');} //...1
x === 1 && console.log('こんにちは') //...2
しかし、2の書き方はおすすめしません。
というのも、右式が実行されるかどうかが曖昧になり、思わぬバグの温床になりかねないからです。
そのため、基本的に論理演算子の後ろに、関数の呼び出し、インクリメント/デクリメント演算子、代入演算子等の値を実際に操作するような式を含めるのは避けましょう。
とはいっても、ショートカット演算にも使いどころがあります。
let msg = '';
msg = msg || 'こんにちは、世界!';
console.log(msg); //結果:こんにちは、世界!
上記のように変数msgがfalsyな値の場合にデフォルト値として「こんにちは、世界!」を代入できます。
##ビット演算子
ビット演算は、整数を2進数で表現したときに各桁に対して論理計算を行う演算のことをいいます。
また、ビット演算子はビット論理演算子とビットシフト演算子の2つに分けることができます。
###ビット論理演算子
10進数 2進数 10進数
6 0110
3 &0011
-------
0010 → 2
論理積では上記のようにどちらのビットが1(true)の場合には1、どちらかのビットが0(false)の場合には0になります。
そして、否定演算子の結果は少し複雑です。
10進数 2進数 10進数
10 1010
-------
0101 → -11
結果が「-11」になるのに疑問を抱く方もいらっしゃるでしょう。
これは、否定演算子が正負を表す符号も反転させているためです。
2進数で負数を表す際には**「ビット列を反転させて1を加えたものが絶対値になる」**というルールがあります。
そのため、上記の例だと「0101」を反転させた「1010」に1を足した「1011」がその絶対値になり、返ってくる値が「-11」になるというわけです。
###ビットシフト演算子
10進数 2進数 10進数
10 1010
------- <<1
10100 → 20
上記は左ビットシフト演算子を使用した場合の例です。
ビットシフト演算子はその桁を指定された桁だけ、左もしくは右にシフトします。
上記は、左シフトであるため右側の桁は「0」で埋められます。
その結果「10100」になり、10進数に変換した「20」となります。
##その他の演算子
###delete演算子
delete演算子はオペランドに指定した変数や配列の要素、オブジェクトのプロパティを削除します。
削除に成功した場合にはtrue、失敗した場合にfalseを返します。
let ary = ['JavaScript', 'Ajax', 'ASP.NET'];
console.log(delete ary[0]); //結果:true
console.log(ary); //結果:[1:"Ajax", 2:"ASP.NET"]・・・①
let obj = {x:1, y:2};
console.log(delete obj.x); //結果:true
console.log(obj.x); //結果:undefined
let obj2 = {x:obj, y:2};
console.log(delete obj2.x); //結果:true
console.log(obj); //結果:{y: 2}・・・②
let data1 = 1;
console.log(delete data1); //結果:false
console.log(data1); //結果:1・・・③
data2 = 10;
console.log(delete data2); //結果:true
console.log(data2); //結果:エラー(data2は存在しない)
上記の結果から以下のことがわかります。
①配列の要素を削除した場合には、指定した要素が削除されるだけで後ろの要素が繰り上がるわけではない(インデックス番号は変化しない)
②プロパティを削除した場合にも、プロパティそのものが削除されるだけで、プロパティが参照するオブジェクトが削除されるわけではない。
③明示的に宣言された変数を削除することはできない。
###typeof演算子
typeof演算子は、オペランドに指定した変数やリテラルのデータ型を表す文字列を返します。
以下が実行例です。
let num = 1;
console.log(typeof num); //結果:number
let str = 'こんにちは';
console.log(typeof str); //結果:string
let flag = true;
console.log(typeof flag); //結果:boolean
let ary = [1,2,3];
console.log(typeof ary); //結果:object
let obj = {x:1, y:2};
console.log(typeof obj); //結果:object
typeof演算子では配列もオブジェクトも「object」が返ってくることを覚えておきましょう。
##まとめ
今回は演算子について記述しました。
演算子はなんとなく利用していましたが、いろいろルールがあり、これらを把握しておかないと思わぬバグにつながるかもしれません。
これからは今回記述したことを理解した上で使用していこうと思います。