JavaScript 数値と文字列の相互変換

# JavaScript では 数値 文字列 の変換が複雑

JavaScript の型変換は標準的な機能がいくつかあります。そのいくつかの方法が細かな所で仕様が異なっているので知っておかないと思わぬバグに遭遇します。

というか遭遇したのでまとめておきました。動作確認用のテストコードを含めて記載しています。

細かく動作確認したい人の参考になったらいいなと、思います。

「+文字」とか「文字 - 0」とか「数値 + ''」といった、可読性の低そうでトリッキーなコードは除外します。詳しくは後述します。→[「変な記号でキャストしない」](#変な記号でキャストしない)

# 数値 から 文字列

数値から文字列への変換は必ず変換ができるので比較的楽です。

String(value)「Stringキャスト」か (value).toString()「toStringメソッド」 を使うのがよいです。


```js
// Stringキャスト
var value = 123;
var text = String(value);

// value.toString()メソッド
var value = 123;
var text = value.toString();
```

この２つがあります。

ほぼ全ての場面で、Stringキャストで事足りそうですが、toString には toString(進数) を指定して、2進数とか16進数の形で出力できるので高機能です。高機能版を常に使いたい気持ちになるのですが、

toStringは 次の場合にエラーで落ちてしまいます。気をつけなければいけません。

```js
var value = null;
var text = value.toString();
// TypeError: Cannot read property 'toString' of null

var value; // value = undefined;
var text = value.toString();
// TypeError: Cannot read property 'toString' of undefined
```

null や undefined は toString プロパティがないですよ。というエラーになります。

null や undefined は数値ではないので、数値から文字列への変換では考慮しない、という事ではありますが、そうはいっても実際のコードで直面する場面は数値だと思っていたけど null が入っているということがよくあり、その時にエラーになって落ちるということになってしまうので、かなり気をつけなければいけない問題です。

ですので、進数変換などしない場合は String(値) を使うようにしましょう。

細かな動きがわかるテストコードは次のところで記載しています。
NaN や Infinity に対しても実行しているので参考にしてください。

https://github.com/standard-software/partsjs/blob/v4.9.1/source_code/convert/convert.test.js#L107

# 文字列 から 数値

さきほどの「数値から文字列の変換」には変換できないという状況はないので楽だったのですが、逆に「文字列から数値への変換」変換できない文字列が確実にあるので、少し複雑になります。

やり方としては Number(value)「Numberキャスト」と parseInt(value, 進数) と parseFloat(value) があります。

```js

var value = '123';
var n = Number(value);

var value = '123';
var n = parseFloat(value);

var value = '123';
var n = parseInt(value, 10);
```

parseIntの第二引数の10は10進数を表します。、2進数 16進数 なども指定できるので高機能です。

上記のような単純な変換ならNumber()もparseFloatもparseIntも全て対応しています。

ですが、空文字を指定したり、null や undefined を指定したりするとややこしいことがおこります。

parseInt は名前の通り、整数にしか対応していません。

Numberキャストも、parseFloat parseInt 全ては前後空白があっても変換してくれますが、Numberキャストは 中間空白があったり アルファベットが混ざっっていると変換ができないことを示して NaN を返します。parseFloat parseInt は途中に変な文字があってもその前までに数値文字列があればそれで変換するように動作します。

NaN については後述します。→[「数値型なのに数値じゃない値 NaN」](#数値型なのに数値じゃない値-nan)

また、Numberキャスト特有の挙動として Number(null) は 0 に変換し、Number(undefined) は NaN にしてしまう、という動作があります。

null と undefined をしっかりわけて把握しておかないと、戻ってくる挙動が異なってしまい、思わぬ不具合の原因になりますのでこちらも特に気をつけましょう。

また、数値配列を与えたときの変換も異なります。

と、まあ、さまざまな問題がありまくり、文章で書いていてもカオス的なのでこちらもテストコードを書きましたのでご参考ください。

https://github.com/standard-software/partsjs/blob/v4.9.1/source_code/convert/convert.test.js#L700


# 変な記号でキャストしない

「+文字」とか「文字 - 0」とか「数値 + ''」といった、トリッキーな短いコードで型を変換するコードが JavaScriptのプログラマの中で一定数の支持を集めています。

Google で「JS 型キャスト」とか検索したら出てくるいくつかのページでこういうのが紹介されていて
トリッキーで短いコードは打鍵回数が減るので、コードを書く時に楽ができる！知ってる人だけ優越感に浸れる！
「( ・∀・)ｲｲ!!」
とかなってますが、全然よくねーよです。

これらは結局はキャストされているだけなので、String() や Number() と同じことをしているだけなので動作は変わりません。文字入力数が異なるだけです。

まともなプログラマなら変な記号での型変換は使ってはいけません。ソースコードの意図がわからなくなるからです。

プログラムは可読性が命です。プログラマは可読性の高いプログラムを書くべきで、可読性の低いプログラムは常に悪です。読み取りにくく後から読むのが辛くなるコードは自分や他の人の生産性を将来にわたって下げ続けるので可能な限りさけるべきです。

プログラミングはパズルじゃないので、極力わかりやすくするために、後々から楽をするために今努力をして数文字くらいはパチパチと入力してください。

どうしてもやりたければ、こんな風に可読性をたかめるためにラッピングしておくべきです。
「コードを書く時に楽ができる！知ってる人だけ優越感に浸れる！」の思想になっている人には通じにくいのかもしれませんが....

```js

const toNumberTest01 = value => {
  return +value;
}

const toNumberTest02 = value => {
  return value - 0;
}

const toStringTest01 = value => {
  return value + '';
}
```

# 数値型なのに数値じゃない値 NaN

NaN は数値だけど「数値ではない」ことを示す不思議な値です。ほとんど使われませんし積極的に使うものでもないのですが、時々でてきます。

Stringに対する空文字「''」や、オブジェクトに対するnull、と同様に数値に対してのNaN という値になります。


# まとめ。

JavaScript の数値、文字列、の相互変換は知っておかなければいけないことが結構あるので大変ですが、気をつけてね。ってことです。

で、
不自然な変換などが行われなくて、あまり気にしなくていいように、テストコードのページにも乗っている代替関数を用意しています。

parts.js というライブラリの中に含めています。
standard-software/partsjs: JavaScript Code Parts TypeSafe Library Compatible with any js platform
https://github.com/standard-software/partsjs


変な変換について、気にかけることがなくなるように変なものが入ってきたら変換しないようにしている関数になります。

与える引数の型を間違ったら変換できないとエラー出す関数
numberToString()
stringToNumber()
stringToInteger()

変換できない場合は例外を出さずに指定デフォルト値を返す関数
stringToNumberDefaut()
stringToIntegerDefault()

与える引数の型を関係なく変換したいなら
toString()
toNumber()
toNumberDefault()
toInteger()
toIntegerDefault()

とか用意しています。
ご参考にどうぞ。