スポンサーリンク

JavaScriptの動かないコード (中級編) nullが0以上0以下と認識されてしまう


以下のJavaScriptコードが意図した動作をしないのは,なぜですか。(制限時間1分)


やりたい事:

  • ラジオボタンの中で,どれかボタンが選択されたかを検証する。
  • 何も選択されていない場合,警告のメッセージを表示。
<body>

どれか選択して下さい。<br>

<input type="radio" name="hoge" value="0"> 0 <br>
<input type="radio" name="hoge" value="1"> 1 <br>
<input type="radio" name="hoge" value="2"> 2 <br>
<input type="radio" name="hoge" value="3"> 3 <br>


<input type="button" value="値を検証" onclick="validate_value()">


<script language="JavaScript">

// ラジオが選択されたかどうかを検証する
function validate_value(){

	// 値を取得する
	var val = get_radio_value();
	
	// 有効な値か?
	if( val >= 0 )
	{
		// OKの場合
		alert( "有効な値が選択されています。(値=" + val + ")" );
	}
	else
	{
		// NGの場合
		alert( "ラジオが未選択です。値を選択してください。" );
	}

}


// ラジオボタンで選択されている数値を返します。
// もし,何も選択されていない場合,nullを返します。
function get_radio_value()
{
	var val = null;

	// name属性によってradioの要素を全部取得
	var radio_elems = document.getElementsByName("hoge");
	
	// チェックされている物の値を保存
	for( var i = 0; i < radio_elems.length; i ++ )
	{
		if( radio_elems[ i ].checked )
		{
			// 数値に変換しておく
			val = parseInt( radio_elems[ i ].value, 10 );
		}
	}
	
	return val;
}


</script>


</body>





答え


発生する不具合


IEでもFirefoxでも,ラジオが未選択の場合

「有効な値が選択されています。(値=null)」

と表示されてしまう。


( val >= 0 ) の所で,nullが有効な値として通過してしまっている。

理由

なんと・・・以下の式が成立する。

  • null >= 0 である。
  • null <= 0 である。


数値比較の際nullは,0以上・0以下とみなされる。


しかも

  • null != 0 である。


0以上,0以下だが,0ではないのだ。



数学的にはありえないが,JavaScriptではこれが仕様である。

null と 0 の比較CommentsAdd Star
http://d.hatena.ne.jp/higeorange/2008...
抽象的関係比較アルゴリズム (The Abstract Relational Comparison Algorithm) によると null が +0 になる


ECMAスクリプト仕様書:型変換
http://www2u.biglobe.ne.jp/~oz-07ams/...
nullを数値に変換すると+0になる

単なる0ではなく,内部値「+0」として扱われる,というのがまたややこしい。

JavaScriptで「+0」と書いても「0」と同じとみなされるが,そうではなくてJavaScriptの処理系自体が内部で「+0」という数学値を仮想的に持っているという事だ。

下記の式が成り立つ。

  • +0 <= 0 である。(したがってnull <= 0)
  • +0 >= 0 である。(したがってnull >= 0)


さらに,大小の比較ではなく等価の比較の場合,nullの数値変換が行なわれない(ToNumber(x)ではなくType(x)により比較がなされる)ので,単純に

  • null != 0

となる。


回避策

数値と比較した場合の比較式の中で型変換が発生してしまう,という事をふまえて,val != null という修正でよいだろう。