やあ、調子はどうだい?
今日も元気に `undefined is not a function` なんていう愛嬌のあるエラーと格闘していることだろう。
フロントエンドの現場でバリデーションやAPIから飛んできた数値データのパース処理を書いているとき、ふと「これ、本当に安全な有限数か?」と不安になって `isFinite` を使ったことはないかい?
そして、何気なくグローバルの `isFinite()` を書いたつもりが、リントツールやシニアのレビューアから「おい、それ `Number.isFinite()` に書き換えといて」とツッコミを入れられた経験はないだろうか。
今日は、この「一見すると同じように動く二つの関数」の決定的な違いについて、JavaScriptの歴史的な泥臭さと、ブラウザのエンジンが裏側でやっている生々しい処理を含めて徹底的に解説しよう。
中級からもう一歩抜け出して「JavaScriptの仕様を完全に掌握しているプロ」になるためのパスポートだと思って、最後までついてきてほしい。
—
1. 結論:何が違うのか?
まずは結論からいこう。二者の最大にして唯一の違い、それは「暗黙の型変換(Type Coercion)を行うかどうか」だ。
- グローバルの `isFinite(val)`
- 引数を強制的に数値に変換(`Number(val)`)してから有限数かどうかを判定する。
- `Number.isFinite(val)`
- 型変換を一切行わない。 引数が「そもそも数値型であり、かつ有限数である」ときだけ `true` を返す。
たったこれだけの違いだが、この仕様の差が、実務の現場でバグを生むか、それとも未然に防ぐかの分水嶺になる。次の章で、その深淵を覗いてみよう。
—
2. なぜグローバルの `isFinite` は危険なのか?(仕様とブラウザの裏側)
JavaScriptは、誕生初期の「おもちゃのスクリプト言語」と呼ばれていた頃の名残を今なお色濃く引きずっている。その最大の象徴が、この「勝手に型を合わせようとするおせっかい(暗黙の型変換)」だ。
グローバルの `isFinite` は、ES2015 (ES6) でモダンな `Number.isFinite` が生み出されるはるか昔、1997年の ECMAScript 1 から存在する由緒ある(そして厄介な)グローバル関数だ。
こいつに渡された値は、内部的に以下のような旅路をたどる。
1. ToNumber 抽象操作の実行: 引数 `val` が数値(Number)でなければ、無理やり数値に変換しようとする。
- 文字列の `”123″` は `123` になる。
- 空文字 `””` やスペースだけの `” “` は、なんと `0` に変換される。
- ブリアンの `true` は `1`、`false` は `0` になる。
- `null` は `0` になる。
- 配列(`[1]` や `[]`)やオブジェクトは、なんだかんだあって最終的に数値に変換されるか、あるいは `NaN` になる。
2. 有限数チェック: 変換された結果が `NaN`、`+Infinity`、`-Infinity` のいずれでもなければ `true` を返す。
「空文字が 0 に化ける」という恐怖
現場で一番やらかしがちなのが、フォームの入力値チェックだ。
ユーザーが何も入力していない空文字 `””` をバックエンドに送る前にフロント側でチェックしたつもりが、グローバルの `isFinite(“”)` を使っていると、これが `true`(有限数である)と判定されてしまう。なぜなら、`Number(“”)` は `0` だからだ。
「入力必須の数値欄なのに、未入力のままパスして送信エラーになった」というバグを踏んだことがあるなら、犯人はこいつだ。
—
3. 実務で即戦力になるコード比較
百聞は一見に如かず。実際にコードを書いてブラウザのコンソールや Node.js で動かしてみよう。以下のコードをそのままコピーして実行してみてくれ。
/
- グローバルの isFinite と Number.isFinite の挙動比較
/
// — 1. 数値のケース(両者とも同じ) —
console.log(isFinite(42)); // true – 普通の数値
console.log(Number.isFinite(42)); // true – 普通の数値
// — 2. 特殊な数値のケース(両者とも同じ) —
console.log(isFinite(Infinity)); // false – 無限大は有限数ではない
console.log(Number.isFinite(Infinity)); // false
console.log(isFinite(NaN)); // false – NaN は有限数ではない
console.log(Number.isFinite(NaN)); // false
// — 3. 【ここが重要】型変換の罠のケース —
// 文字列の数値
console.log(isFinite(“123”)); // true – 文字列 “123” が 123 に変換されてセーフ
console.log(Number.isFinite(“123”)); // false – 型が「文字列」なので即アウト!これが安全。
// 空文字・空白文字
console.log(isFinite(“”)); // true – おっと! “” は Number(“”) -> 0 に変換されてしまう!
console.log(Number.isFinite(“”)); // false – 型が違うので正しく弾く。素晴らしい。
// ブリアン型
console.log(isFinite(true)); // true – true は Number(true) -> 1 に変換される
console.log(Number.isFinite(true)); // false – 型が違うので弾く
// null
console.log(isFinite(null)); // true – null は Number(null) -> 0 に変換される!
console.log(Number.isFinite(null)); // false – 型が違うので安全
// 配列やオブジェクト
console.log(isFinite([5])); // true – [5] -> “5” -> 5 に変換される泥臭さよ…
console.log(Number.isFinite([5])); // false – 当然 false
どうだろう?
グローバルの `isFinite` がいかに「おせっかいな優しさ」を発揮して、予期せぬバグの温床になり得るかがよく分かったはずだ。
—
4. チーフアーキテクトからの実践的なアドバイス
実務の現場において、私たちは常に「予期せぬ入力」と戦っている。APIのレスポンス、URLのクエリパラメータ、ユーザーが自由に入力できるフォームなど、JavaScriptに渡ってくるデータ型はカオスそのものだ。
だからこそ、以下のベストプラクティスをチームの共通認識として持ってほしい。
ベストプラクティス:グローバルの `isFinite` は「封印」せよ
特別な理由がない限り、コードベース内でグローバルの `isFinite()` を使う必要性は現代のフロント開発においてはほぼゼロだ。むしろバグの温床になるので、 ESLint などの静的解析ツールで禁止(あるいは `Number.isFinite` への置き換えを強制)することを強く推奨する。
例えば、ESLintを使っているなら、以下のようなルール(またはカスタムルールやTypeScriptの型ガード)を意識するとチーム全体のコード品質が劇的に跳ね上がる。
// .eslintrc のイメージ(no-restricted-globals などの活用)
{
“rules”: {
“no-restricted-globals”: [
“error”,
{
“name”: “isFinite”,
“message”: “予期せぬ型変換を防ぐため、代わりに Number.isFinite を使用してください。”
}
]
}
}
TypeScriptを使っている場合
もしプロジェクトで TypeScript を導入しているなら、`Number.isFinite` は型ガード(Type Guard)としても非常に優秀に機能する。
`Number.isFinite(val)` が `true` を返した瞬間、TypeScriptのコンパイラは `val` の型を `number` に絞り込んでくれるため、その後の計算や処理で型安全を完全に担保できる。
—
おわりに
JavaScriptという言語は、初心者には優しく、中級者には油断ならない罠を仕掛け、上級者にはその深い仕様の妙を味方につけさせる、実に奥深い言語だ。
「動くからいいや」で済ませていた小さな関数一つをとっても、その背景にある仕様(この場合は暗黙の型変換の有無)を理解しているかどうかで、書くコードの堅牢性は圧倒的に変わってくる。
今日の帰りにでも、自分のプロジェクトのコードベースで `isFinite` と検索してみてほしい。もしグローバルのものが残っていたら、ドヤ顔で `Number.isFinite` に書き換えて、プルリクエストを出してやるといい。チームのメンバーも「おっ、こいつできるな」と一目置くはずだ。
それじゃあ、今日もクリーンでバグのないコードを書いていこう! Happy Coding!

コメント