素の JavaScript は非常に型が緩い言語です。動作しないことを期待する様な入力でも結果的に動作することがよくあります。この特性が文字列型を数値型に変換する時にも起きる例を紹介します。具体的には次です。
Number('1'); // 1
Number('12e3'); // 12000
Number(''); // 0
Number('aaa') // NaN
Number(false); // 0
Number(null); // 0
Number(true); // 1
Number({}); // NaN
Number([]); // 0
Number([7]); // 7
Number([7, 1, "a"]); // NaN
Number(['aaa']); // NaN
数値として解釈できる文字列が渡される場合、その通りに文字列が数値になっています。しかしながらNumberによるキャストは単にNumber型に変換するという意味合いで、false, null, true をはじめとした文字列以外のものも数値として変換されています。もし文字列を入力として数値を出力したい場合、文字列でも数値でもないモノが入力された場合は NaN を返したいです。次の様に Number.parseFloat や Number.parseInt を使うとこれは比較的期待通りに動作します。
Number.parseFloat('1'); // 1
Number.parseFloat('12e3'); // 12000
Number.parseFloat(''); // NaN
Number.parseFloat('aaa') // NaN
Number.parseFloat(false); // NaN
Number.parseFloat(null); // NaN
Number.parseFloat(true); // NaN
Number.parseFloat({}); // NaN
Number.parseFloat([]); // NaN
Number.parseFloat([7]); // 7
Number.parseFloat([7, 1, "a"]); // 7
Number.parseFloat(['aaa']); // NaN
与えられた要素に数字がない場合、NaN になります。toString した場合の挙動が大変怪しいですが、ただの Number() によるキャストより随分ましです。この toString というのは Number.parseInt, Number.parseFloat の仕様にある、文字列型以外の数字が渡された場合はまずその与えられた値を文字列型に変換し改めて parseXXXX にかける、という挙動に関連しています。
ECMAScript® 2023 Language Specification#sec-parsefloat-string
ECMAScript® 2023 Language Specification#sec-parseint-string
真に厳密にするならば次の様に関数を作るのが一番です。
function str2num(str){
if(typeof str === 'number'){
// Number型の場合は変換なしで返す
return str;
}
if(typeof str !== 'string'){
// Number型でも String 型でもないならば NaN を返す
return Number.NaN;
}
// String 型ならば Number.parseFloat にかける
return Number.parseFloat(str)
}
str2num('1'); // 1
str2num('12e3'); // 12000
str2num(''); // NaN
str2num('aaa'); // NaN
str2num(false); // NaN
str2num(null); // NaN
str2num(true); // NaN
str2num({}); // NaN
str2num([]); // NaN
str2num([7]); // NaN
str2num([7, 1, "a"]); // NaN
str2num(['aaa']); // NaN