JavaScriptの動かないコード (初級編) parseIntで返り値が0になるエラー
以下のJavaScriptコードが意図した動作をしないのは,なぜですか。(制限時間1分)
やりたい事:
- 「2008年12月から何か月経ったか」を計算する。
<input type="button" value="期間を表示" onClick="f()"> 月を選択してください。 → 2009年の <select id="select_month"> <option value="01">01</option> <option value="02">02</option> <option value="03">03</option> <option value="04">04</option> <option value="05">05</option> <option value="06">06</option> <option value="07">07</option> <option value="08">08</option> <option value="09">09</option> <option value="10">10</option> <option value="11">11</option> <option value="12">12</option> </select> 月。 <script language="JavaScript"> function f() { var elem_select = document.getElementById( "select_month" ); // 選択されている月を取得 var str = elem_select.options[ elem_select.selectedIndex ].value; // 数値に変換 var num = parseInt( str ); // 経過月数を表示 alert( "2008年12月からの経過月数は," + num + "ヵ月です。" ); } </script>
答え
01〜07 と,10〜12を選択したときはうまく動く。
しかし「08」と「09」を選択して実行すると,IEでもFirefoxでも「経過月数は,0ヵ月です」と表示される。
8と9だけ,文字列から数値にうまく変換できていない。
原因
JavaScriptでは,リテラルの先頭に0が付くと8進数とみなされる。
下記のコードを実行すると・・・
alert( 010 + 01 ); // 10 + 1 = 11 のつもり
11ではなく9と表示される。なぜなら
- 8進数の 010 は10進数では「8」
- 8進数の 01 は10進数では「1」
文字列の場合も同じ。
引用符で囲った中身が数字列で,
- 先頭が0〜であれば8進数
- 先頭が0x〜であれば16進数
となる。
冒頭のコードでは,桁揃えのために0埋めを行なっていたのが仇となった。
2桁の0埋めだと,00から99までの中で,戻り値がおかしくなるのは08と09のケースだけ。
これは発見されにくい。
ブラウザ上で01から12まで(つまり月)の入力を求めるような個所がある場合,テストケースとしては
- 境界値:01, 12
- 中間の値をいくつか(6とか)
をまず想定するだろう。
しかしさらに念のため,
- 意図しない8進数変換のせいで,"08"・"09"の解釈がバグを起こさないか?
というのも,テスト項目に加えたいところ。
なおコードの修正案としては,明示的に10進数として認識させるためにparseIntのオプションを指定して
// 数値に変換 var num = parseInt( str, 10 );
とすればよい。
参考:
parseIntの挙動(Javaとの仕様の違い)
http://blogs.wankuma.com/kox/archive/...javascriptで8と9のときだけエラーになるってみんなが首をかしげているときがあって8進数になってたというオチのときがありましたね。
なんとなく桁をそろえようと頭に0をつけたのが運のつきw
Mozillaのサイト:整数
https://developer.mozilla.org/ja/Core...
整数
整数は 10 進数、16 進数、8 進数で表現可能です。10 進整数リテラルは先頭の 0(ゼロ)を除いた、数字の連続からなります。整数リテラルにおいて先頭の 0(ゼロ)はそれが 8 進数であるということを指します。先頭の 0x(または 0X)は 16 進数を指します。16 進整数は数字(0 から 9)と a から f および A から F のアルファベットからなります。8 進整数は 0 から 7 までの数字のみからなります。
8 進整数リテラルは廃止予定であり、ECMA-262 第 3 版から除かれています。JavaScript 1.5 では依然として後方互換のためにそれをサポートしています。
早く廃止してほしいような。
※関連するエントリー:
JavaScriptの動かないコード (初級編) 数値判定の方法・・・入力値が有効な整数かどうかチェック
http://language-and-engineering.hatenablog.jp/entry/20080830/1220070507
JavaScriptの動かないコード (初級編) if文の分岐がおかしい
http://language-and-engineering.hatenablog.jp/entry/20080915/1221451639