JavaScript の map 関数の仕様がクソ

JavaScript で、wtf なコードを発見。

['10','10','10','10','10'].map(parseInt)

// 実行結果
[10, NaN, 2, 3, 4]


なんだ・・・これ・・・は・・・!?




解答編
map に渡した関数には二つの引数が渡される。第一引数はリストの要素。第二引数に、要素のインデクスが渡される。

従って

['10','10','10','10','10'].map(parseInt)

というコードは、下記のように実行される。

parseInt('10',0);
parseInt('10',1);
parseInt('10',2);
parseInt('10',3);
parseInt('10',4);

parseInt は通常は引数一つを渡して使用するが、第二引数も指定することができる。第二引数は第一引数の基数。第一引数が10進数の場合は10、第一引数が2進数の場合は2。で、改めて実行されるコードを眺めてみる。

// 第二引数に 0 を渡した場合は10進数としてみなされ、'10' の数値表現の 10 (10進数表記) なので 10 が返る
parseInt('10',0); -> 10

// 1進数は存在しないので NaN が返る。
parseInt('10',1); -> NaN

// 10 (2進数表記) なので、10進数に直して、2。
parseInt('10',2); -> 2

// 10 (3進数表記) なので、10進数に直して、3。
parseInt('10',3); -> 3

// 10 (4進数表記) なので、10進数に直して、4。
parseInt('10',4); -> 4


というわけで、JavaScript 的には仕様に沿った挙動らしい。


仕様に沿ってるとは言えこのような明らかに直感に反する挙動はクソでしかない。
map で受け取る関数は引数一つというのがどの言語でも当たり前のように認識されているのに、JavaScript はそれを守らなかったためにこのようなコードが生まれてしまう。
驚き最小の原則を守って欲しいものである。