JavaScript には isNumber
というメソッドなく、整数かどうか判定する Number.isInteger()
と有限数かどうか判定する Number.isFinite()
, isFinite()
だけなので、数値かどうか判定したい時は独自実装するかライブラリをつかうしか無いのですが暗黙の型変換があるので意外とハマりどころがあります。( TypeScript 使え!ってのは無しで、
結論から書けば、typeof
が number
なもので、NaN
と Infinity
を除外すれば有限数な数値かどうか判定できる。
const isNumber = (n) => { return typeof(n) === 'number' && n - n === 0; };
of
Number.isFinite(n);
暗黙の型変換のヤバイやつ
JavaScript で簡易的に数値に変換する方法として - 0
する方法があります。
"10" - 0; // => 10 "a" - 0; // => NaN
これを利用した数値かどうか判定するような関数
const isNumber = (n) => { const v = n - 0; if ( v || v === 0 ) { return true; } return false; };
渡される値がある程度決まっている場合は問題ないのですが、特定の値の時意図しない動作になってしまう事があります
✅isNumber( 1 ); // true ✅isNumber( -1 ); // true ✅isNumber( 10.1 ); // true ✅isNumber( -1.1 ); // true ✅isNumber( 5e3 ); // true ✅isNumber( 10e+3 ); // true ✅isNumber( 10e-3 ); // true ✅isNumber( 0xff ); // true ✅isNumber( Math.PI ); // true ✅isNumber( parseInt('012') ); // true ✅isNumber( parseInt('012.5') ); // true ✅isNumber( Infinity ); // true ✅isNumber( -Infinity ); // true ✅isNumber( '10' ); // true ✅isNumber( '-10' ); // true ✅isNumber( NaN ); // false ⛔️isNumber( null ); // true ✅isNumber( undefined ); // false ⛔️isNumber( true ); // true ⛔️isNumber( false ); // true ⛔️isNumber( '' ); // true ⛔️isNumber( ' ' ); // true ✅isNumber( 'string' ); // false ⛔️isNumber( [] ); // true ⛔️isNumber( [1] ); // true ✅isNumber( {} ); // false ✅isNumber( {a: 1} ); // false ✅isNumber( function() {} ); // false
これは - 0
で数値化する際に暗黙の型変換で数値に変換されてしまう値があるためです
null - 0; //=> 0 true - 0; // => 1 false - 0; // => 0 "" - 0; // => 0 " " - 0; // => 0 [] - 0; // => 0 [1] - 0; //=> 1
数値かどうか判定する
数値でかつ NaN
, Infinity
は除外したい
コード
const isNumber = (n) => { if ( typeof(n) === 'number' && Number.isFinite(n) ) { return true; } return false; };
or
const isNumber = (n) => { if ( typeof(n) === 'number' && n - n === 0 ) { return true; } return false; };
👇 test
✅ isNumber( 0 ); // true ✅ isNumber( 1 ); // true ✅ isNumber( -1 ); // true ✅ isNumber( 10.1 ); // true ✅ isNumber( -1.1 ); // true ✅ isNumber( 5e3 ); // true ✅ isNumber( 10e+3 ); // true ✅ isNumber( 10e-3 ); // true ✅ isNumber( 0xff ); // true ✅ isNumber( Math.PI ); // true ✅ isNumber( parseInt('012') ); // true ✅ isNumber( parseFloat('012.5') ); // true ✅ isNumber( Infinity ); // false ✅ isNumber( -Infinity ); // false ✅ isNumber( NaN ); // false ✅ isNumber( null ); // false ✅ isNumber( undefined ); // false ✅ isNumber( true ); // false ✅ isNumber( false ); // false ✅ isNumber( "10" ); // false ✅ isNumber( "-10" ); // false ✅ isNumber( "" ); // false ✅ isNumber( " " ); // false ✅ isNumber( "string" ); // false ✅ isNumber( [] ); // false ✅ isNumber( [ 1 ] ); // false ✅ isNumber( {} ); // false ✅ isNumber( { a: 1 } ); // false ✅ isNumber( function() {} ); // false
文字列の数字も true にする
先の数値判定に文字列で数字になるものを true にする判定を追加すればOK
const isNumberAllowString = (n) => { const type = typeof(n); if ( type === 'number' && Number.isFinite(n) ) { return true; } if ( type === 'string' && n.trim() !== '' && Number.isFinite(n - 0) ) { return true; } return false; };
👇 test
✅ isNumberAllowString( 0 ); // true ✅ isNumberAllowString( 1 ); // true ✅ isNumberAllowString( -1 ); // true ✅ isNumberAllowString( 10.1 ); // true ✅ isNumberAllowString( -1.1 ); // true ✅ isNumberAllowString( 5e3 ); // true ✅ isNumberAllowString( 10e+3 ); // true ✅ isNumberAllowString( 10e-3 ); // true ✅ isNumberAllowString( 0xff ); // true ✅ isNumberAllowString( Math.PI ); // true ✅ isNumberAllowString( parseInt('012') ); // true ✅ isNumberAllowString( parseFloat('012.5') ); // true ✅ isNumberAllowString( "10" ); // false ✅ isNumberAllowString( "-10" ); // false ✅ isNumberAllowString( Infinity ); // false ✅ isNumberAllowString( -Infinity ); // false ✅ isNumberAllowString( NaN ); // false ✅ isNumberAllowString( null ); // false ✅ isNumberAllowString( undefined ); // false ✅ isNumberAllowString( true ); // false ✅ isNumberAllowString( false ); // false ✅ isNumberAllowString( "" ); // false ✅ isNumberAllowString( " " ); // false ✅ isNumberAllowString( "string" ); // false ✅ isNumberAllowString( [] ); // false ✅ isNumberAllowString( [ 1 ] ); // false ✅ isNumberAllowString( {} ); // false ✅ isNumberAllowString( { a: 1 } ); // false ✅ isNumberAllowString( function() {} ); // false
解説的なもの
typeof で判定
typeof()
が number
がになるもので判定すると先の暗黙の変換で数値になるものを除外することができる
typeof( null ); // => "object" typeof( true ); // => "boolean" typeof( false ); // => "boolean" typeof( "" ); // => "string" typeof( " " ); // => "string" typeof( [] ); // => "object" typeof( [1] ); // => "object"
NaN
, Infinity
を除外する
NaN
, Infinity
は number
なので別の条件で除外する
isFinite
isFinite
渡された値が有限数かどうかを判定します。
cf. isFinite() - JavaScript | MDN
JavaScript には isFinite
と Number.isFinite
がある。
isFinite
… 暗黙の型変換が行われるNumber.isFinite
… 暗黙の型変換を行わない
※ IEでは使えない cf. Number: isFinite | Can I use
e.g.
Number.isFinite( Infinity ); // => false Number.isFinite( -Infinity ); // => false Number.isFinite( NaN ); // => false
同値の引き算を利用する
同値で引き算をすると有効数だと 0 になるが、Infinity
, NaN
は NaN
になることを利用して除外する
Infinity - Infinity; // => NaN -Infinity - (-Infinity); // => NaN NaN - NaN ; // => NaN
文字列の数字を判定
string - 0
で数値化して、 isFinite()
で NaN
と Infinity
になるものを弾く
"a" - 0; // => NaN "Infinity" - 0; // => Infinity "-Infinity" - 0; // => Infinity
ただし空文字列だけは 0
になってしまうので別途除外する必要がある
"" - 0; // => 0; " " - 0; // => 0; "".trim(); // => "" " ".trim(); // => ""
所感
文字列の数字も許可したい場合は、is-number というライブラリを使うのが楽だと思います。
[参考]
- Number.isInteger() - JavaScript | MDN
- Number.isFinite() - JavaScript | MDN
- isFinite() - JavaScript | MDN
- 作者:Jonathan Wexler
- 出版社/メーカー: 翔泳社
- 発売日: 2019/09/25
- メディア: 単行本(ソフトカバー)