今年はやりたいことがあるので、少し更新頻度落とします(といっても、2週間以上も空けるつもりはなかった・・・)。
JavaScriptでは、頭に!をつけるとその値を否定したブーリアン値になります。例えば下記のような感じです。
console.log(!true); //=> false console.log(!false); //=> true console.log(!100); //=> false console.log(!"str"); //=> false console.log(!null); //=> true
そしてさらにその値に!を着けたら否定の否定なので、!をつけてtrueのものはfalse、falseになるものはtrueとなる。つまり、頭に!!をつけて得た値は、Booleanメソッドを使った場合と同じ結果になる。
console.log(!!true); //=> true console.log(Boolean(true)); //=> trie console.log(!!false); //=> false console.log(Boolean(false));//=> false console.log(!!100); //=> true console.log(Boolean(100)); //=> false console.log(!!"str"); //=> true console.log(Boolean("str"));//=> true console.log(!!null); //=> false console.log(Boolean(null)); //=> false
で、本題ですが、JavaScriptで演算子を使わない値(プリミティブ値)で、頭に!!をつけてfalseになる値は、false,数値の0,空文字,null,undefined,NaNの6種類だけです。
console.log(!!false); //=>false console.log(!!0); //=>false console.log(!!""); //=>false console.log(!!null); //=>false console.log(!!undefined); //=>false console.log(!!NaN); //=>false
これ以外の演算子を使わない値はすべてtrueになります。一見、falseになりそうな空オブジェクトや空配列、Infinityや文字列の”0″はtrueになります。
console.log(!!{}); //=>true console.log(!![]); //=>true console.log(!!Infinity); //=>true console.log(!!"0"); //=>true
さて、ここで演算子を使わない値を限定しました。なぜなら、演算子を使うとキリがないからです。一応、例を少しあげると下記のような値(というより、演算子をつけてるので式といったほうがいいかもしれません)が頭に!!をつけるとfalseとなります。なお、今回はわざわざ頭に!!をつけていますが、比較演算子(>や<、二つ以上つづく=の演算子)を使った式の場合、!!を使わなくても結果はBoolean値になります。
console.log(!!(1-1)); //=>false console.log(!!(2>2)); //=>false console.log(!!(0===null)); //=>false console.log(!!(“a”>1)); //=>false console.log(!!(1>=”a”)); //=>false console.log(!!(NaN===NaN));//=>false
さて、ここで「あれ?」となった人もいるかもしれません。自分も先日、「あれ? 何でだ?」と思って記述ミスがないか見なおしてみましたが、どこも間違ったところはありませんでした。どうやら、NaN同士を==や===で比較した場合、結果はfalseとなるようです。
参考:NaN – JavaScript | MDN
例えば下記のようなcheckNaNという関数を作った場合、引数にNaNをいれても”NaNじゃない”という結果になってしまいます。
function checkNaN(val){ val = val - 0; if(val===NaN){ console.log("NaNです"); }else{ console.log("NaNじゃない") } } checkNaN(0); //=>"NaNじゃない" checkNaN(1); //=>"NaNじゃない" checkNaN("str"); //=>"NaNじゃない" checkNaN(true); //=>"NaNじゃない" checkNaN(null); //=>"NaNじゃない" checkNaN(undefined); //=>"NaNじゃない" checkNaN(NaN); //=>"NaNじゃない"
NaNかどうか調べたいときは、isNaNメソッドを使ってNaNかどうかを調べるのがよさそうです。
function checkNaN(val){ val = val - 0; if(isNaN(val)){ console.log("NaNです"); }else{ console.log("NaNじゃない") } } checkNaN(0); //=>"NaNじゃない" checkNaN(1); //=>"NaNじゃない" checkNaN("str"); //=>"NaNです" checkNaN(true); //=>"NaNじゃない" checkNaN(null); //=>"NaNじゃない" checkNaN(undefined); //=>"NaNです" checkNaN(NaN); //=>"NaNです"
ここで、trueやnullがNaNじゃないとなっているのは、true-0が1、null-0が0になるからです。今回はわざわざ値から0を引いて数値変換していますが、実はそんなことをしなくても同じ結果になります。
function checkNaN(val){ if(isNaN(val)){ console.log("NaNです"); }else{ console.log("NaNじゃない") } } checkNaN(0); //=>"NaNじゃない" checkNaN(1); //=>"NaNじゃない" checkNaN("str"); //=>"NaNです" checkNaN(true); //=>"NaNじゃない" checkNaN(null); //=>"NaNじゃない" checkNaN(undefined); //=>"NaNです" checkNaN(NaN); //=>"NaNです"
これじゃあ困るという場合は、同じ値を同値比較した場合にfalseになるのがNaNだけというのを利用して、下記のようにすると、引数がNaNの場合だけが”NaNです”となります。
function checkNaN(val){ if(!(val===val)){ // NaNかどうかを調べている console.log("NaNです"); }else{ console.log("NaNじゃない") } } checkNaN(0); //=>"NaNじゃない" checkNaN(1); //=>"NaNじゃない" checkNaN("str"); //=>"NaNじゃない" checkNaN(true); //=>"NaNじゃない" checkNaN(null); //=>"NaNじゃない" checkNaN(undefined); //=>"NaNじゃない" checkNaN(NaN); //=>"NaNです"
非常にわかりづらいので、こういう手法を取るときはコメントを書いたほうがいいと思います。というより、できるだけ使わないようにするのがいいと思います。
ところで、NaNはなぜ同値比較するとfalseになるのか理由を考えると、例えば、『”aiueo”-0』と『”abcde”-0』の比較は等しくなってほしくないからじゃないかと思いました(実際のところどうしてか分かってません)。で、そこで、Infinity(無限大)はどうなんだと思いました。結論からいうと、Infinity同士の比較はtrueになります。なので下記の比較はすべてtrueとなります(Infinityになる値は右記を参考:【Javascript】0で割ると? at softelメモ)。
console.log((1/0)===(10000/0)); //=>true console.log((Math.pow(2,1024))===Infinity); //=>true console.log((Infinity*1000)===(Infinity/1000)); //=>true
少し違和感があるかもしれませんが、こういうものだと思いましょう。
コメント