🐙

parseIntはもう怖くない

に公開

ここはJavaScript老人会。

TLDR

  • JavaScriptのparseIntは基数を指定しない場合の動作がブラウザ間で異なる時代があった
  • parseInt("010")10 になったり 8 になったりする
  • 16進表記の場合を除きデフォルトの基数を10とする仕様にES5で定まり、各ブラウザも対応した

昔の挙動のブレの話

昔のJavaScriptでは parseInt("010") の出力は 10 だった。
これは0始まりの数字列を8進数で解釈するため。たぶんC言語由来。

この8進数と解釈する挙動がES3で非推奨となり、ES5では明確に仕様から削られデフォルトの基数が10とされた。
しかし、すべてのブラウザが一斉にESに準拠するわけでもないので、ブラウザごとに挙動が異なる時代があった。

例えば2013年ごろだと、ChromeとFirefoxで差があった。

parseInt("010") // → Chrome 24では `10`, Firefox 18では `8`

MDNのparseIntの記事には昔その辺りの注意書きがあったりした。

Although discouraged by ECMAScript 3 and forbidden by ECMAScript 5, many implementations interpret a numeric string beginning with a leading 0 as octal. The following may have an octal result, or it may have a decimal result. Always specify a radix to avoid this unreliable behavior.

この記述は2021年に削られている。日本語版へも後に反映
https://github.com/mdn/content/pull/2187


ちなみに、今も互換性テーブルには0から始まる文字列を8進数ではなく10進数でパースするのがどのバージョンからだったのかが載っている。
parseIntのブラウザーの互換性テーブル

現在の仕様

ES5以降の仕様では、基数を指定しない限り基本は10進数で解釈すること、0x〜の場合のみ16進数表現として解釈することが明記されている。

If radix coerces to 0 (such as when it is undefined), it is assumed to be 10 except when the number representation begins with "0x" or "0X"
https://tc39.es/ecma262/2025/#sec-parseint-string-radix より

とはいえ、じゃあparseIntを何も考えずに数字列をパースするのに使っていいかというとそうではない。
空白を除き文字列中の最初に現れる整数表現っぽいものをパースするという挙動なので、他にもハマる瞬間はあると思う。

parseInt(" 1234_567890") // → 1234

実際使用する場面では、外部から入力される不特定の文字列をどう扱うかといった、普通のアプリケーション設計をちゃんとしようねというだけの話ではある。

あとがき

そういやES6あたりで改善されてたはずだけどどうだったっけ?とふと思い出して書いてみた。
ちなみに、素稿はChatGPTに参考リンクと雑に考えていた目次をChatGPTにぶっこんで書かせてみた。が、全然自分好みじゃないテイストの文面だったり、余計な要素を足してきたりしたので、まぁ素稿だしなと捨てて文面は全部自分で書いた。そんな長大に書く内容でもないし。
とはいえ、一旦まがいなりにも完成文がある状態に持っていってから「じゃあこうしよう」に思考のステップを進められるのはいい感じだったかも。

参考記事・リンク

▼Firefoxではv21で挙動が変わった
https://developer.mozilla.org/ja/docs/Mozilla/Firefox/Releases/21#javascript
https://bugzilla.mozilla.org/show_bug.cgi?id=786135

▼MDNへの反映
https://github.com/mdn/content/pull/2187

▼昔ハマった人の記事など
https://stackoverflow.com/questions/14542377/timestamp-conversion-difference-between-chrome-and-firefox
https://liginc.co.jp/web/js/31018
https://www.pxt.jp/ja/diary/article/195/
https://qiita.com/isseium/items/6c7841122fb380a51fe6

Discussion