not good but great

プログラミング、アート、映画・本の感想について書きます。

Javasciptで二重否定を使う意味、「関数名」と「関数名()」の違い

二重否定「!!」の意味

以下はブラウザがCanvasをサポートしているかチェックしているソースである。
・ソース元
http://tympanus.net/Development/InteractiveParticlesSlideshow/js/particlesSlideshow.js

var canvas = document.createElement('canvas');
// Browser supports canvas?
if(!!(capable)) {
	//省略
}
else {
	console.error('Sorry, switch to a better browser to see this experiment.');
}		
function capable() {
	return canvas.getContext && canvas.getContext('2d');
}

if文の条件式で「!!」が使われていてなんじゃこりゃと思った。

二重否定「!!」がわからない理由

Q1:2回否定したら同じでは?

"true"もしくは"false"を2回否定したら元通りになると思ったので、使う理由がわからない。

Q2:関数名だけで関数って実行できるの?

if文の条件式に入っているのは関数名だけ。関数を実行するのなら「関数名()」のはず。「!!」を使用する際には関数名だけで良いのだろうか。

Q1の解答:objectか"undefined"が入るので同じにはならない

objectのとき

var hoge = {};

console.log(typeof hoge);//obejct
console.log(hoge);//obejctの中身
console.log(!hoge);//false
console.log(!!hoge);//true

objectを否定すると、falseになることをうまく利用している。

"undefined"のとき

//canvasがサポートされてないとき
var canvas = document.createElement('canvas');//undefined

定義されていないので"undefined"が入る。

console.log(test);//undefined
console.log(!test);//true
console.log(!!test);//false

今度は"undefined"を否定するとtrueになることに注目している。「!!」を使うと、falseに変換できる。

objectと"undefined"をBooleanで扱うことができるようになった。

二重否定「!!」を使うメリット

・記述が短い

if (typeof a === "undefined") {
}

条件式で型判定をやろうとすると書くのが長くなる。

・"undefined"は予約語ではなく、古いブラウザでは上書きが可能

二重否定「!!」を使うデメリット

・objectと"undefined"以外に対して「!!」を使うとおかしくなる
"true","false",0が返ると条件判定がうまくできない。


・参考
nullを使う方法が紹介されている
JavaScript:undefined値の判定: Architect Note


javascript - Can someone explain this 'double negative' trick? - Stack Overflow

Q2の解答:関数名()で行うのが正しい

「関数名」と「関数名()」の違いは、前者は関数のアドレスを、後者は関数が返す値を返していることだ。

・参考
関数名()と関数名のみの違い - とにかくやってみるブログ - Ingwer Design

「関数名」と「関数名()」の場合を実際に試してみよう。

var a;
console.log(a);//undefined
console.log(!a);//true
console.log(!!a);//false

まず「undefined」を準備する。

関数名だけの場合

function test(){
    console.log('hogehoge');//出力されない
    return a;
}

console.log(typeof test)//function
console.log(test);//関数がそのまま表示
console.log(!test);//false
console.log(!!test);//true

「関数名」だけだと関数が定義されているか(関数のアドレスが用意されているか)を判定している。だから戻り値は関係ないので、「!!test」は"true"になる。

関数名()の場合

console.log(typeof test());//undefined
console.log(test());//undefined
console.log(!test());//true
console.log(!!test());//false

関数名()の場合、関数を実行するので戻り値が評価対象になる。だから「!!test」は"false"になる。

結論

元のソースは関数名だけが書いているので、Canvasのサポートの有無に関わらず、"!!capable"は"true"だ。だから判定ができていないと思う・・・。間違っていたのかなー。