型を変換する

生田 陸人
ゆめさくエンジニア / 現役ソフトウェアエンジニア
編集 LuaGate編集部

このレッスンで分かること

  • Number(値) で数値へ、String(値) で文字列へ明示的に変換できます
  • parseIntparseFloat は数字で始まる文字列から数を取り出します
  • + は片方が文字列だと連結になるため、意図しない結果を生みます

型を変換する とは

文字列と数値を相互に変換します。入力欄から届いた "3" を数値に直して計算できるようになる回です。

数字に見えても文字列

前のレッスンの最後で見たとおり、"3"3 は別物です。入力欄から受け取った値は、見た目が数字でもすべて文字列として届きます。この状態で計算しようとすると、期待とは違う結果になります。

const yearsText = "3"; console.log(yearsText + 1); // "31" 連結されてしまう console.log(yearsText - 1); // 2 なぜか引き算はできる

足し算だけが連結になり、引き算は数値として計算されます。+ は文字列の連結にも使う記号なので、片方が文字列だと連結が優先されるためです。- には連結の意味が無いので、JavaScript が文字列を数値に変換してから計算します。

この「勝手に変換される」動きを 暗黙の型変換 と呼びます。便利に見えますが、結果が読みにくくなるため、自分で明示的に変換するほうが安全です。

判断の基準 暗黙の型変換に頼らず、変換したい場所で自分で変換する。これだけで型に起因するバグの大半は防げます。

数値へ変換する

文字列を数値にする方法は主に 3 つあります。

console.log(Number("3")); // 3 console.log(parseInt("3", 10)); // 3 console.log(parseFloat("3.5")); // 3.5

Number() は値全体を数値として読もうとします。数値として読めない文字が 1 文字でも混ざっていると NaN になります。parseInt()parseFloat() は先頭から数字として読める部分だけを取り出し、途中で読めなくなったらそこで止まります。

変換結果の早見表

実際の挙動を並べると、次の通りです。手を動かして確かめながら読んでください。

結果補足
Number("3")3素直に変換される
Number("3.5")3.5小数もそのまま
Number(" 5 ")5前後の空白は無視される
Number("")0空文字は 0 になる
Number("3年")NaN余計な文字があると失敗
Number(null)0null は 0 として扱われる
Number(undefined)NaNundefined は数にできない
Number(true)1true は 1、false は 0
parseInt("3年", 10)3読める所まで取り出す
parseInt("3.9", 10)3小数点以下は切り捨て
parseInt("年3", 10)NaN先頭が数字でないと失敗
parseInt("", 10)NaN空文字は数にできない
parseFloat("3.5kg")3.5小数として読める所まで

特に注意したいのが Number("")0 になる点と、parseInt("")NaN になる点の違いです。未入力の扱いを間違えると「入力していないのに 0 として計算された」という不具合につながります。

NaN は Not a Number の略で、数値型でありながら「数として意味を持たない」ことを表す特別な値です。typeof NaN"number" になります。NaN は計算に混ざると結果もすべて NaN になるため、変換に失敗したことに気付かないまま画面に NaN と表示される事故がよく起きます。

現場の話 parseInt の第 2 引数 10 は 10 進数として読むという指定です。省略しても現代の環境ではほぼ 10 進数として扱われますが、意図を明示するために書く習慣を付けておくと安全です。

文字列へ変換する

数値を文字列にするには String() を使います。

console.log(String(3)); // "3" console.log(String(3.5)); // "3.5" console.log(String(true)); // "true" console.log(String(null)); // "null" console.log(String(undefined)); // "undefined"

String() はどんな値でも文字列にできるため、Number() のように失敗することがありません。nullundefined もそれぞれ "null" "undefined" という文字列になります。

数値には toFixed() という便利なメソッドもあります。小数点以下の桁数をそろえた文字列を返します。

const views = 1234.567; console.log(views.toFixed(1)); // "1234.6" 文字列になる点に注意

toFixed() の戻り値は数値ではなく文字列です。そのまま計算に使うと、また連結が起きてしまいます。

変換の落とし穴

暗黙の型変換は、演算子によって振る舞いが変わります。代表的なものを整理すると、次の通りです。

結果何が起きているか
"3" + 1"31"数値が文字列に変換され連結
1 + "3""13"順番が違っても連結
"3" - 12文字列が数値に変換され引き算
"3" * 26掛け算も数値として計算
true + 12true が 1 に変換される
"" + 1"1"空文字との連結

+ だけが特別扱いだと覚えておけば、ほとんどの混乱は避けられます。数値として扱いたいなら、+ を書く前に Number() を通しておきます。

const yearsText = "3"; const years = Number(yearsText); console.log(years + 1); // 4 正しく計算できる

覚え方 外から入ってきた値は、受け取った直後に変換して型をそろえる。この一手間を入口で済ませておくと、後の処理で型を気にせずに済みます。

変換する場所を決めておく

変換をどこで書くかは、コードの読みやすさを大きく左右します。おすすめは、値を受け取った直後にまとめて変換してしまう書き方です。関数の先頭で const years = Number(yearsText); と変換しておけば、以降の行では数値として安心して扱えます。

反対に、使う直前で毎回 Number() を書くと、同じ変換が何か所にも散らばります。1 か所でも書き忘れると、そこだけ文字列のまま計算されて連結が起きます。入口で 1 回だけ変換する、という方針を決めておいてください。

よくある間違い

1 つ目は、変換せずに足し算してしまうケースです。

const workCountText = "3"; const total = workCountText + 1; console.log(total); // "31" 期待は 4

Number(workCountText) + 1 と書けば 4 になります。

2 つ目は、Number("")0 になることを見落とすケースです。

const input = ""; // 未入力 console.log(Number(input) + 1); // 1 未入力なのに計算が通る

未入力かどうかは、変換する前に元の文字列で確かめる必要があります。この判定の材料は次のレッスンで扱います。

3 つ目は、NaN になったことに気付かないケースです。

const years = Number("3年"); console.log(years); // NaN console.log(years + 1); // NaN 画面に NaN と表示される

NaN は他の値と比べても等しくならないという特殊な性質があるため、判定には Number.isNaN(years) を使います。まずは「変換は失敗しうる」という前提を持つことが大切です。

要件

  1. 関数名は nextYearLabel、引数は yearsText (文字列または数値) の 1 つ
  2. Number で数値に変換してから 1 を足す
  3. 戻り値は 4 年目 の形の文字列。数値を String で文字列にしてから連結する

入出力例

nextYearLabel("3")"4 年目" nextYearLabel(3)"4 年目" nextYearLabel(" 5 ")"6 年目" nextYearLabel("0")"1 年目" nextYearLabel("")"1 年目"

ヒント

main.js
main.js
学習モード

メモ

型を変換する

⌘S で保存