[JavaScript] parseIntでハマった。

2013/08/21

こんにちは。きんくまです。

ふだんparseIntをよく使ってます。文字列を数値に変換する関数ですね。
例えばbutton1とかいうボタンの名前から末尾の番号取得したりとかそういうのです。

var index = parseInt(buttonName.substr('button'.length));

んで、実はあまり挙動をよく知らなかったのでハマりました。
こんな感じのコードがあります。

var logStr = [];
logStr.push("1 -> " + parseInt("1"));
logStr.push("2 -> " + parseInt("2"));
logStr.push("5 -> " + parseInt("5"));
logStr.push("7 -> " + parseInt("7"));
logStr.push("8 -> " + parseInt("8"));
logStr.push("9 -> " + parseInt("9"));
logStr.push("10 -> " + parseInt("10"));
logStr.push("11 -> " + parseInt("11"));
logStr.push("15 -> " + parseInt("15"));
logStr.push("17 -> " + parseInt("17"));
logStr.push("18 -> " + parseInt("18"));
alert(logStr.join('\n'));

logStr = [];
logStr.push("01 -> " + parseInt("01"));
logStr.push("02 -> " + parseInt("02"));
logStr.push("05 -> " + parseInt("05"));
logStr.push("07 -> " + parseInt("07"));
logStr.push("08 -> " + parseInt("08"));
logStr.push("09 -> " + parseInt("09"));
logStr.push("10 -> " + parseInt("10"));
logStr.push("11 -> " + parseInt("11"));
logStr.push("15 -> " + parseInt("15"));
logStr.push("17 -> " + parseInt("17"));
logStr.push("18 -> " + parseInt("18"));
alert(logStr.join('\n'));

一つ目のグループは文字列が1桁でも0をつけないタイプ。
二つ目のグループは文字列が1桁だと前に0を詰めるタイプです。
で、実行結果がある環境だと、

//1回目のアラート
1->1
2->2
5->5
7->7
8->8
9->9
10->10
11->11
15->15
17->17
18->18

//2回目のアラート
01->1
02->2
05->5
07->7
08->8
09->9
10->10
11->11
15->15
17->17
18->18

という感じに、0が前にあっても数値を評価してくれます。
ところが、少し古めの環境(iOS5以下、Android3.0以下だったり。Androidは端末依存かも)だと、

//1回目のアラート
1->1
2->2
5->5
7->7
8->8
9->9
10->10
11->11
15->15
17->17
18->18

//2回目のアラート
01->1
02->2
05->5
07->7
08->0  //注目!
09->0  //注目!
10->10
11->11
15->15
17->17
18->18

となりました。08,09が0に変換されてます。
なんでなのかな?と調べてみたところ、下記ページが見つかりました。

>> parseInt – JavaScript | MDN

引用すると

入力 string が “0” で始まっている場合、基数は 8 (8 進表記)になります。この機能は、非推奨です。

基数の無い 8 進数の解釈
困った事に、ECMAScript 3 では、parseInt の引数とする数字の先頭の文字が 0 で有った場合の解釈を実装側に委ねていました。その為、多くの実装で先頭が 0 から始まる数値文字列が 8 進数として解釈され、しかしながら必ず 8 進数になるとも限りません。

つまり、parseIntの第二引数の基数を省略した場合、8進数で評価されることがあるってことですね。8進数なので、8を超えた数値は無効なので、0と評価されているって感じです。

ただ、これだと使いづらいのか、最近は10進数として評価されてるみたいです。

>> parseInt が 0 で始まる文字列を 8 進数でなく 10 進数としてパースするようになりました

なので、最近のOSでは問題なく動いていたということみたいです。

でもでも、古いブラウザでもきちんと評価したい!って場合には、第二引数を10にしておけば問題なしです。

logStr.push("08 -> " + parseInt("08", 10));
logStr.push("09 -> " + parseInt("09", 10));

そんな感じです。ではでは。


自作iPhoneアプリ 好評発売中!
フォルメモ - シンプルなフォルダつきメモ帳
ジッピー電卓 - 消費税や割引もサクサク計算!

ページトップへ戻る