【Javascript】"08" "09" を parseInt した時に0になって困った話
おつかれさまです🌞
アイドルに課金するために働いているなりたです。
以前、Javascriptで"04/01"のような日付を表す文字列から
月と日を数値として取り出そうとした際に困ったことを
今回は書いていこうと思います📝
やろうと思ったこと
DBのとあるテーブルに"04/01"というような形で日付が文字列として保存されているので、それを取得する
取得した文字列から月と日を取得し、それぞれを数値として別の変数に代入する
サンプルソース
const date_string = "04/01";
const date_array = date_string.split("/");
const month = parseInt(date_array[0]);
const day = parseInt(date_array[1]);
console.log("month", month, typeof(month));
console.log("day", day, typeof(day));
出力内容
month 4 number
day 1 number
想定通り数値に変換できていますね。
よし、これで date_string に実際にDBの値を入れて動作確認してみよう!
しかし…
動作確認中、おかしなことが起こりました。
DBから8月9日の日付を取得した際…
const date_string = "08/09";
const date_array = date_string.split("/");
const month = parseInt(date_array[0]);
const day = parseInt(date_array[1]);
console.log("month", month);
console.log("day", day);
出力内容
month 0
day 0
!?
08 と 09 のどちらも 0 になっている😱
どうしてこんなことに…
ひとまず検索してみよう。
そう思いGoogleさんで「parseInt 08」と入力してみると、サジェストで同じ事象と思われる検索ワードが出てきました🔍️
「parseInt 08 09」と検索したところ、正にこれだ!という内容の以下のページがヒットしました。
つまり何が起こった?
上記のページの内容から、今回の原因をざっくりまとめてみると…
parseInt() は第二引数として基数を指定することができる。
parseInt() の第二引数を指定しないと、第一引数の値を見て自動で解釈される。
“0” から始まる文字列は8進数の値だと認識されてしまっていた。
parseInt(“04”) や parseInt("01") も8進数だと認識されていたが、10進数と同じ数値なため気付かなかった。
ということだったようです。
しかし、Javascript を数年触っているのになぜ今になって初めてこの事象に遭遇したのか…
先ほどの参考ページの内容には以下のような記述もありました。
ブラウザでは、parseInt() の第二引数が未指定の場合、10進数にするものが多いとのこと。
これで気付きました。
単純に私が今までクライアント側Javascriptを触っている機会が圧倒的に多いから遭遇しなかっただけということを…🤯
開発者ツールのコンソールで試すと、確かに parseInt("08") が 0 にはならず 8 になりました。
今回、この事象が発生した際は
珍しくサーバ側Javascriptを触っていました😇
対策
この事象に遭遇して以降、同じように文字列を数値に変換する場合には以下のように対処することにしました。
parseInt() を使う場合は、必ず第二引数を指定する。
クライアント側、サーバ側問わず指定する!
そもそも parseInt() を使わずに Number() を使用する。
Javascriptに限らず数値関係の処理は思わぬ挙動に遭遇することがあるので、今後も注意して行きたいと思います🧐
おまけ
良い機会なので parseInt() で色々試してみました。
"007" を8進数に変換すると?
parseInt("07", 8)
// 7
parseInt("007", 8)
// 7
頭の 0 を増やしても影響ありませんでした。
文字列に数値以外が含まれていると?
parseInt("2024nen", 10)
// 2024
parseInt("reiwa6nen", 10)
// NaN
数値の後ろに数値以外の文字が付いている分には大丈夫なようです。
文字列に空白が含まれていると?
parseInt(" 1234 ", 10)
// 1234
半角/全角スペースを入れてみましたが無視されました。
全角の数値は?
parseInt("1234", 10)
// NaN
parseInt("string", 10)
// NaN
文字列はNaNに変換されるのですが、同じ変換結果になりました。