大事なことなので何度でも言うべきでしょうか。
[javascript]true or false論理値の挙動については、いまいち感覚的に理解しにくい印象です
Crockfordの言う通り、===と!==を使いましょう。
Demo
==と!=がいかに挙動不審かを、実際に表にします。textareaには表に入れたい値を入力してみてください。void(0)と1/0とparseInt('nan')は、確実にundefinedとInfinityとNaNを得るための方策です(ES5ではきちんと定数になったみたいですが)。
DHTML Source
JS Source
$id = function(id){ return document.getElementById(id) };
toStr = function(o){
return typeof(o) === 'number' ? o : JSON.stringify(o);
};
showem = function(tbody, op, objstr){
var d = document,
tr = d.createElement('tr'),
th = d.createElement('th'),
td = d.createElement('td'),
objs = eval('[' + objstr + ']'),
pred = function(lhs, rhs){
return eval( '('+toStr(lhs)+op+toStr(rhs)+')' );
}
tbody.innerHTML = '';
th.appendChild(d.createTextNode(op));
tr.appendChild(th);
objs.forEach(function(obj){
th = th.cloneNode(false);
th.appendChild(d.createTextNode(toStr(obj)));
tr.appendChild(th);
});
tbody.appendChild(tr);
objs.forEach(function(lhs){
tr = tr.cloneNode(false);
th = th.cloneNode(false);
th.appendChild(d.createTextNode(toStr(lhs)));
tr.appendChild(th);
objs.forEach(function(rhs){
td = td.cloneNode(false);
td.appendChild(d.createTextNode(toStr(pred(lhs,rhs))));
td.style.backgroundColor = pred(lhs, rhs) ? '#ccffcc' : '#ffcccc';
tr.appendChild(td);
});
tbody.appendChild(tr);
});
};
見ての通り、x === xが成立しないのはNaNのみです。これであればなんとか覚えられます。
型変換
それでは明示的に型を変換したい場合はどうしたらよいでしょうか?
幸いにしてそれほど難しくはありません。
!! to boolify
強制的にbooleanにするには、!!を頭につけます。
p( !!void(0) );
p( !!null );
p( !!false );
p( !!true );
p( !!0 );
p( !!1 );
p( !!(1/0) );
p( !!parseInt('nan') );
p( !!'' );
p( !!'0' );
p( !!'0.0' );
p( !![] );
p( !!{} );
単項演算子!が論理否定を意味する言語系ならほぼ必ず使えるテクニックです。
+ to numify
強制的にnumberにするには、+を頭につけます。+[]が0で、+{}がNaNである点には注意が必要ですが。
p( +void(0) );
p( +null );
p( +false );
p( +true );
p( +0 );
p( +1 );
p( +-1);
p( +(1/0) );
p( +parseInt('nan') );
p( +'' );
p( +'0' );
p( +'0.0');
p( +[] );
p( +{} );
あと、確実に単項演算子になっているよう気をつけた方がよいでしょう。
var x = 0;
p( 1
+x
);
p(+ +x); /* +(+x), not ++x */
p(x);
1*も使えます。
p( 1*void(0) );
p( 1*null);
p( 1*false );
p( 1*true );
p( 1*0 );
p( 1*1 );
p( 1*-1);
p( 1*(1/0) );
p( 1*parseInt('nan') );
p( 1*'' );
p( 1*'0' );
p( 1*'0.0');
p( 1*[] );
p( 1*{} );
特にPerl usersにも注意を喚起したいのは、0+は使えないという点です。私も時々引っかかります。
p( 0+void(0) );
p( 0+null);
p( 0+false );
p( 0+true );
p( 0+0 );
p( 0+1 );
p( 0+-1);
p( 0+(1/0) );
p( 0+parseInt('nan') );
p( 0+'' );
p( 0+'0' );
p( 0+'0.0');
p( 0+[] );
p( 0+{} );
二項演算子としての+では、右辺の型に引きずられてしまうのですね。
''+ to stringily (or use JSON.stringify())
強制的にstringにするには、''+を頭につければOK。もっとも単純に文字列にした場合にそれに意味があるかどうかは別問題ですが。
p( ''+void(0) );
p( ''+null);
p( ''+false );
p( ''+true );
p( ''+0 );
p( ''+1 );
p( ''+(1/0) );
p( ''+parseInt('nan') );
p( ''+'');
p( ''+'0');
p( ''+'0.0');
p( ''+[] );
p( ''+{} );
ES5では標準装備のJSON.stringify()を使ってもいいでしょう。ただし見てのとおり、NaNでもInfinityでもnullにしてしまう点に注意が必要ではありますが。
p( JSON.stringify(void(0)) );
p( JSON.stringify(null) );
p( JSON.stringify(false) );
p( JSON.stringify(true) );
p( JSON.stringify(0) );
p( JSON.stringify(1) );
p( JSON.stringify(1/0) );
p( JSON.stringify(parseInt('nan')) );
p( JSON.stringify('') );
p( JSON.stringify('0') );
p( JSON.stringify('0.0') );
p( JSON.stringify([]) );
p( JSON.stringify({}) );
One more thing
そうそう。
[javascript]true or false配列が空かどうかが(value == false)で判別できる
これはやめましょう。きちんと配列かどうかを確認した上で、value.lengthを調べるべきです。たとえば…
/*
* works for arrays and array-like objects like arguments
*/
function isEmpty(ary){
return 'length' in ary && ary.length === 0;
};
JavaScriptの演算子、特に==をめぐる混乱は、最初の設計でPerlを中途半端に意識したところに問題がありそうな気がします。Perlで演算子が数値用と文字列用に分かれているのにはれっきとした理由があったのにそこがスルーされてしまったところとか…
Dan the Man with too Many Variables to Compare and Coerce

このブログにコメントするにはログインが必要です。
さんログアウト
この記事には許可ユーザしかコメントができません。