JavaScript Tips | 基本・共通ユーティリティ:基本判定・変換 – 浮動小数変換

JavaScript JavaScript
スポンサーリンク

「浮動小数変換」とは何をするものか

浮動小数変換は、「文字列や整数などの値を“小数を含む数値”として安全に扱える形にする」ことです。
金額(小数点以下の税率や手数料)、割合、重さ、距離、レート、単価など、業務では「小数を含む数値」を扱う場面がとても多くあります。

JavaScript の number 型は整数と小数を区別しませんが、「入力値をどう解釈するか」「変換に失敗したときどうするか」「小数点以下をどこまで許すか」は、業務ごとにきちんと決める必要があります。
そのルールをユーティリティ関数に閉じ込めるのが、実務的な浮動小数変換の考え方です。


Number と parseFloat の基本的な挙動を押さえる

Number による変換

Number(value) は、「その値を数値として解釈できるか」を試し、ダメなら NaN を返します。

console.log(Number("10.5"));      // 10.5
console.log(Number("  10.5  "));  // 10.5
console.log(Number("10.5kg"));    // NaN
console.log(Number(""));          // 0
console.log(Number(null));        // 0
console.log(Number(undefined));   // NaN
console.log(Number("abc"));       // NaN
JavaScript

ここで重要なのは、「空文字や null が 0 になる」「途中に文字が混ざると NaN になる」という点です。
業務的に「空文字を 0 とみなしてよいのか?」「null を 0 にしてよいのか?」は要件によって変わるので、そのまま使うのではなく、ルールを決めてラップしたくなります。

parseFloat による変換

parseFloat は、「文字列の先頭から読めるところまで小数として読む」関数です。

console.log(parseFloat("10.5"));     // 10.5
console.log(parseFloat("10.5kg"));   // 10.5
console.log(parseFloat("  10.5px")); // 10.5
console.log(parseFloat("kg10.5"));   // NaN
JavaScript

Number("10.5kg") は NaN ですが、parseFloat("10.5kg") は 10.5 になります。
「単位付き文字列から数値部分だけ取りたい」ときには便利ですが、「入力値として厳密にチェックしたい」ときには少し“ゆるい”挙動です。


NaN を必ず意識することが浮動小数変換の肝

浮動小数変換で一番危険なのは、「変換に失敗して NaN になったのに、そのまま計算に使ってしまう」ことです。

const value = Number("abc");  // NaN

console.log(value + 10);      // NaN
console.log(value * 2);       // NaN
console.log(value > 0);       // false
console.log(value < 0);       // false
console.log(value === NaN);   // false
JavaScript

NaN は「何と比較しても false」「自分自身とすら等しくない」という特殊な値です。
NaN かどうかを判定したいときは、Number.isNaN(value) を使います。

console.log(Number.isNaN(NaN));            // true
console.log(Number.isNaN("abc"));          // false
console.log(Number.isNaN(Number("abc")));  // true
JavaScript

業務コードでは、「浮動小数への変換に失敗したらどうするか?」を必ず決めておく必要があります。
エラーにするのか、null にするのか、0 に丸めるのか――ここを曖昧にすると、静かにバグが増えていきます。


実務向けの toFloatOrNull を設計する

「数値として解釈できないものは null にしたい」「空文字や空白だけは“未入力”として扱いたい」という、現場でよくある要件を前提にしたユーティリティを作ってみます。

function toFloatOrNull(value) {
  if (value === null || value === undefined) return null;
  if (typeof value === "string" && value.trim() === "") return null;

  const n = Number(value);
  if (Number.isNaN(n)) return null;

  return n;
}

console.log(toFloatOrNull("10.5"));     // 10.5
console.log(toFloatOrNull("  10.5  ")); // 10.5
console.log(toFloatOrNull("abc"));      // null
console.log(toFloatOrNull(""));         // null
console.log(toFloatOrNull(null));       // null
console.log(toFloatOrNull("10.5kg"));   // null
JavaScript

ここで深掘りしたいポイントは三つあります。

一つ目は、「null / undefined / 空文字・空白だけの文字列は、そもそも変換対象外として null を返す」と決めていることです。
これにより、「未入力」と「不正な数値」を同じ扱い(null)にできます。

二つ目は、「Number で数値に変換したあと、必ず Number.isNaN で失敗を検出している」ことです。
Number(value) をそのまま返すのではなく、「失敗したら null にする」というルールをユーティリティの中に閉じ込めています。

三つ目は、「parseFloat ではなく Number を使っている」ことです。
parseFloat("10.5kg") のような“途中まで数値”の文字列を許したくない場合、Number の方が厳密で、入力バリデーションとして適しています。


小数点以下の桁数をどう扱うかを決める

浮動小数変換では、「小数点以下をどこまで許すか」「表示するときに何桁に丸めるか」も重要な設計ポイントです。
例えば、「税率は小数点以下 3 桁まで」「金額表示は小数点以下 2 桁まで」などです。

変換自体は toFloatOrNull で行い、そのあとで丸め処理を重ねるのが分かりやすい構成です。

function roundTo(value, digits) {
  if (value === null || value === undefined) return null;
  const n = Number(value);
  if (Number.isNaN(n)) return null;

  const factor = 10 ** digits;
  return Math.round(n * factor) / factor;
}

console.log(roundTo(1.23456, 2));  // 1.23
console.log(roundTo(1.23556, 2));  // 1.24
JavaScript

これを組み合わせて、「入力値を浮動小数に変換し、業務で必要な桁数に丸める」ユーティリティを作れます。

function toRoundedFloatOrNull(value, digits) {
  const n = toFloatOrNull(value);
  if (n === null) return null;
  return roundTo(n, digits);
}

console.log(toRoundedFloatOrNull("1.2345", 2)); // 1.23
console.log(toRoundedFloatOrNull("abc", 2));    // null
JavaScript

ここで大事なのは、「変換」と「丸め」を分けて考えることです。
変換は「数値として解釈できるかどうか」、丸めは「業務上どこまでの精度が必要か」という別の問題なので、関数も分けておくと意図が明確になります。


0 や負の値、範囲制限をどう扱うか

浮動小数でも、「0 や負の値を許可するか」「上限・下限をどうするか」を決める必要があります。
例えば、「割引率は 0 以上 1 以下の小数だけ許可したい」という要件なら、次のように書けます。

function toRateOrNull(value) {
  const n = toFloatOrNull(value);
  if (n === null) return null;
  if (n < 0 || n > 1) return null;
  return n;
}

console.log(toRateOrNull("0.2"));   // 0.2
console.log(toRateOrNull("1.0"));   // 1
console.log(toRateOrNull("1.5"));   // null
console.log(toRateOrNull("-0.1"));  // null
console.log(toRateOrNull("abc"));   // null
JavaScript

ここでも、「変換」と「業務ルールとしての範囲チェック」を分けています。
toFloatOrNull は「数値として妥当かどうか」だけを見て、そのあとで「この業務では 0〜1 の範囲だけ許可」といったルールを重ねています。


単位付き文字列を扱いたい場合の parseFloat の使いどころ

CSS の "10.5px""1.2rem" のように、「単位付きの文字列から数値部分だけ取りたい」ケースでは、parseFloat が便利です。

function parseCssFloat(value) {
  if (typeof value !== "string") return null;
  const n = parseFloat(value);
  return Number.isNaN(n) ? null : n;
}

console.log(parseCssFloat("10.5px"));   // 10.5
console.log(parseCssFloat("  10.5em")); // 10.5
console.log(parseCssFloat("px10.5"));   // null
console.log(parseCssFloat("abc"));      // null
JavaScript

ここでも、「文字列の先頭に数値がある場合だけ許可する」「それ以外は null」というルールをはっきりさせています。
parseFloat を“何でもありの変換”として使うのではなく、「この用途専用」としてユーティリティに閉じ込めるのが安全です。


実務での具体的な利用イメージ

例えば、フォームから「税率」と「単価」が文字列で送られてくるケースを考えます。

const raw = {
  taxRate: "0.1",     // 10%
  unitPrice: "1200",  // 税抜き単価
};

const taxRate = toRateOrNull(raw.taxRate);
const unitPrice = toFloatOrNull(raw.unitPrice);

if (taxRate === null || unitPrice === null) {
  console.log("税率または単価が不正です");
} else {
  const tax = toRoundedFloatOrNull(unitPrice * taxRate, 2);
  const total = toRoundedFloatOrNull(unitPrice + tax, 2);

  console.log("税額:", tax);
  console.log("税込金額:", total);
}
JavaScript

ここでは、「文字列をそのまま計算に使わない」「変換に失敗したら null にして、そこで止める」「表示用には必要な桁数に丸める」という方針を徹底しています。
こうしておくと、「’abc’ * ‘0.1’ が NaN になって、そのままどこかに流れていく」といった事故を防げます。


小さな練習で感覚をつかむ

toFloatOrNull, toRoundedFloatOrNull, toRateOrNull を自分で実装して、次のような値を片っ端から試してみてください。
"10.5", " 10.5 ", "10", "0", "-1.2", "1.01", "1.5", "abc", "", " ", null, undefined, "10.5kg" などを渡して、結果をコンソールに出してみると、「どこまでを許容するか」「どこからを不正とみなすか」が自分の中でクリアになってきます。

タイトルとURLをコピーしました