1. はじめに
ある条件の場合に処理を行いたい」、「ある条件となった場合に次へ進みたい」、など特定の条件が満たされているか否かを判断する際に使用するのが「比較演算子」とりわけ「等価演算子」です。プログラミングを行う上で、欠かせないものではないでしょうか。第2回は、この「等価演算子」にフォーカスし、その基本的な性質について理解を深めるため、neqto.jsを使用して詳しく解説していきます。
「neqto.js」は、NEQTO Engine上で動作するJavaScript環境です。ECMAScript 5.1 Editionに対応しています。
2. 等価演算子
等価演算子」は2つの値を比較して等しいか否かをブール値、つまりtrueまたはfalseで返します。もちろんtrueなら一致ということになります。
var a = 1;
print(a == 2); //false
print(a == 1); //true
print(typeof(a == 1)); //boolean
JavaScriptには「緩い等価性(Abstract equality/==)」と「厳格な等価性(Strict equality/===)」があります。前者を「等価演算子(Equals Operator)」、後者を「厳密等価演算子(Strict Equals Operator)」と呼びます。
下記に示すとおり、等価演算子の場合、文字列は数値に置き換えて比較されるため一致となります。一方、厳密等価演算子の場合は一致となりません。
var a = 1;
var b = '1';
print(a == b); //true
これらの性質を理解した上で、==/===どちらを使用すべきか選択することになります。
3. neqto.jsによる動作検証
ここからは、neqto.jsを使用して、さらに深堀していきます。neqto.jsの動作環境について詳しく知りたい方は、下記のリンク先を確認してください。
① -0+0、および0の比較
-0、+0、および0は等価演算子でも厳格等価演算子でも一致します。
print(+0); //0
print(-0); //0
print(+0 === -0); //true
print(+0 == -0); //true
print(+0 === 0); //true
print(-0 === 0); //true
② 0と""の比較
0はブール値のfalseと一致します。""もブール値のfalseと一致します。よって、0と""は論理的に一致します。厳格等価演算子では一致しません。
print(0 == false); //true
print("" == false); //true
print("" == 0); //true
print("" === 0); //false
③ nullとundefinedの比較
nullとundefinedはブール値のfalseと一致しません。trueでも一致しません。よって、nullとundefinedは論理的に一致することにはなりません。しかしながら、nullとundefinedを比較すると一致となります。厳格等価演算子では一致せず、nullとundefinedは別々の扱いとなります。
print(null == false); //false
print(undefined == false); //false
print(null == true); //false
print(undefined == true); //false
print(null == undefined); //true
print(null === undefined); //false
なお、if文の中ではfalseと判定されます。
if(null) { print('It is truthy.'); } else { print('It is falsy.'); } //It is falsy.
if(undefined) { print('It is truthy.'); } else { print('It is falsy.'); } //It is falsy.
** ④ 数値/文字列とnull/undefinedの比較 **
nullとundefinedを等価演算子で比較した場合、一致となりますが、双方ともに数値(例えば0)や文字列(例えば"")との比較では一致しません。すなわち、数値や文字列とは一切一致しないということになります。
print(null == undefined); //true
print(null === undefined); //false
print(0 == undefined);//false
print(0 == null); //false
print("" == null); //false
print("" == undefined); //false
⑤ 数字を表す文字列と数値の比較
数字を表す文字列と数値そのものは一致します。厳格等価演算子では一致しません。
print('123' == 123); //true
print('123' === 123); //false
⑥ プリミティブ文字列とStringクラス文字列の比較
プリミティブ文字列とStringクラスの文字列は一致します。厳格等価演算子では一致しません。
print('abc' == new String('abc')); //true
print('abc' === new String('abc')); //false
⑦ プリミティブ数値とNumberクラス数値の比較
プリミティブ数値とNumberクラスの数値は一致します。厳格等価演算子では一致しません。
print(777 == new Number(777)); //true
print(777 === new Number(777)); //false
** ⑧ 配列と文字列の比較 **
配列はtoString()で得られる文字列と同じ文字列の場合、一致となります。厳格等価演算子では一致しません。
print([1, 2, 3]); //1,2,3
print([1, 2, 3].toString()); //1,2,3
print([1, 2, 3] == '1,2,3'); //true
print([1, 2, 3] == '1, 2, 3'); //false
print([1, 2, 3] === '1,2,3'); //false
⑨ NaNの特殊性
グローバルスコープのNaNは、Number型のプロパティであるNaN、つまりNumber.NaNと同等となります。
print('NaN' in this); //true
print('NaN' in Number); //true
しかし、比較結果は一致しません。
print(NaN == Number.NaN); //false
自分自身と比較しても一致しません。
print(NaN == NaN); //false
print(Number.NaN == Number.NaN); //false
NaNは自分自身とさえも一致しない唯一の値になります。
NaNの特定は、==/===だけでは判断できないように見えますが、この唯一性を応用することで特定可能となります。自分自身と比較した結果がfalseであることがNaNの証となります。実際に検証してみます。
function myIsNaN(val) {
if(val === val) return false;
else return true;
//Same as
//return val !== val;
}
print(myIsNaN(1)); //false
print(myIsNaN('1')); //false
print(myIsNaN(NaN)); //true
print(myIsNaN(Number.NaN)); //true
NaNおよびNumber.NaNはともにtrueとなりました。唯一性からすると、NaNとNumber.NaNは同じであることが分かります。
なお、NaNの特定には、下記の標準メソッドを用いる方法があります。
isNaN(NaN); //true
isNaN(Number.NaN); //true
⑩ オブジェクトの特殊性
プリミティブ文字列とStringクラスの文字列(オブジェクト)は一致します。しかし、別々に作成されたStringクラスの文字列同士の場合は等価演算子であっても一致しません。
print('abc' == new String('abc')); //true
print(new String('abc') == new String('abc')); //false
完全に同じオブジェクト同士の場合だけ一致します。
var a = new String('abc');
var b = a;
print(a == a); //true
print(a == b);//true
まとめ
いかがでしたか。一見比較結果が想定できそうな等価演算子ですが、「等価演算子(==)」および「厳密等価演算子(===)」、どちらを使用するかによって比較結果が異なります。「厳密等価演算子(===)だけ使っておけば間違いないのでは」と考えることもできますが、理解した上で使用するのであれば、等価演算子(==)も便利な側面があります。正しい仕様、特徴、動作を理解して、効率的な使い分けをお勧めします。
リンク
Standard ECMA-262 5.1 Edition ECMAScript® Language Specification - 11.9 Equality Operators