どうも、えいやです。
JavaScriptのよくある落とし穴の話をします。
例えば、'01:24'
のような時刻表示について、時間と分をint
で取ろうと以下のようなコードを書いたとします。
'01:24'.split(':').map(parseInt)
実はこれは正常に動きません。結果は以下となります。
> '01:24'.split(':').map(parseInt)
[ 1, NaN ]
試しに:
区切りとなっている文字列で与えられている数値の数を増やすと、以下のようになります。
% node -v && node
v12.16.3
> '01:02:03:04:05:06'.split(':').map(parseInt)
[ 1, NaN, 0, 0, 0, 0 ]
さて、何が起きているのか正確にわかりますか?
とりあえず意図通りに動かすには、mapが引数として取る関数に引数を与えて、
> '01:02:03:04:05:06'.split(':').map(n=>parseInt(n))
[ 1, 2, 3, 4, 5, 6 ]
とします。
引数を設定するかどうかで動作が変わるので、原因は引数です。
特にScalaなどの他の言語をやっていると見落としがちですが、Array.map
の引数となる関数が取る引数ですが、実は以下のようになっています。
Array.map((currentValue, index, array)=>...);
具体的になにが来ているのかは、こうすると分かりやすいです。
> '01:02:03:04:05:06'.split(':').map(console.log)
01 0 [ '01', '02', '03', '04', '05', '06' ]
02 1 [ '01', '02', '03', '04', '05', '06' ]
03 2 [ '01', '02', '03', '04', '05', '06' ]
04 3 [ '01', '02', '03', '04', '05', '06' ]
05 4 [ '01', '02', '03', '04', '05', '06' ]
06 5 [ '01', '02', '03', '04', '05', '06' ]
parseInt
は、第2引数に基数をとりますので、先程の例ではindex
の値が当てられて順に0,1,2,3,4,5
進数として文字列を数値変換していたようですね。
それを踏まえてfig.2
の振る舞いを見てみましょう。引数が0のときはどうやら10進数と解釈されている様子です。で、"1進数"は常にNaN
。その他の進数では、範囲外の数字が使用されている部分を無視して先頭の0
だけを解釈しているようです。
JavaScriptを始めとした型の判定が甘い言語では、こうしたうっかりミスを起こしがちなので注意しましょう。