JavaScript の不思議な型変換について見ていきましょう。
そもそも言語の性質として JavaScript は型についてかなりおおらかだと言えます。
JavaScript は弱い型付けあるいは動的型付けの言語です。JavaScript では、変数が直接的に特定のデータ型に関連付けられているわけではなく、どの変数にもあらゆる型の値を代入 (および再代入) することができます。
上の MDN の説明にもあるように変数宣言時に型付けをする必要はありません。
また JavaScript の型は時に 暗黙的に変換されます。
要は勝手に別の型に変換されてしまうケースがあるのです。
なんだか危なそうな響きですが、型変換を生かした面白いコードもあるんですよ。
文字列への変換
文字列への変換が起こる例はこちらです。
console.log(1 + "2"); // -> "12"
なんと。。。 JavaScript は 1 + 2 = 12 だと思っているアホの子なのでしょうか。
もちろんそんなことはなく、上の結果は型変換が為せる技です。
typeof(1 + "2");
と実行すると "string"
が返ってくるはずです。つまり JavaScript は文字列と数値を足し合わせた場合、文字列に直して計算し、文字列結合を実行するのです。
ではクイズです。以下を実行するとコンソールに何が出力されるでしょう?
console.log(('b'+'a'+ + 'a' + 'a').toLowerCase()); // -> ???
- "baaa"
- NaN
- "banana"
...
...
...
...
...
...
...
...
...
...
...
...
正解は3の "banana" です!
ちなみに私は初見の時に 2.NaN を選んで撃沈しました。
元ネタはこちらだと言われています
→ javascript - Why is the result of ('b'+'a'+ + 'a' + 'a').toLowerCase() 'banana'? - Stack Overflow
理屈を1つずつ見ていきましょう。
JavaScript はコードを以下のように認識しています。
( ('b') + ('a') + (+'a') + ('a') ).toLowerCase();
顔文字に見えてきましたね
(+'a')
は何を指しているでしょうか?
この + は「単項プラス」という演算子です。
単項プラス演算子 (
+
) は、オペランドの前に置かれ、そのオペランドを評価し、それが数値以外の場合は数値に変換します。
単項プラスは被演算子が数値であればそのまま数値を返し、数値でない場合は数値に変換してくれます。
今回は単項プラスに「a という文字列を数値に変換してね」とお願いしてしまったので、「いやそんなの無理です」ということで NaN
を返されてしまいました。
すると式は以下のように評価されます。
( ('b') + ('a') + NaN + ('a') ).toLowerCase();
実は NaN
は数値型です。
文字列型と数値型が足されると…数値型は文字列に変換され、文字列結合が起こりますね!
'baNaNa'.toLowerCase();
ということで答えは banana です🍌
数値への変換
続いては数値への変換についてみて行きましょう。
console.log("10" - "2") // -> ???
console.log("10" * "2") // -> ???
console.log("10" / "2") // -> ???
実はこれらの式はそれぞれ 8、20、5 と評価されます。
文字列は + を使って結合することができますが、他の演算子を使って計算することができません。
JavaScript は「まあ普通に考えて数値でしょ」と判断してそれとなく数値計算に変換してくれたわけです。 めっちゃいい子ですね。
さて、ここから活躍するのは先ほども触れた単項プラスです。
以下を実行するとどうなるでしょう?
console.log(typeof +"2") // -> ???
こちらは number と評価されます。
文字列を number に変換する方法として Number() を使うことが挙げられますが、実は単項プラスを使っても数値型に変換してくれるんですね。
使えたときはちょっとドヤ顔したくなります(ただしチーム開発ではメンバーとしっかり話し合いましょう👍)
真偽値への変換
JavaScript には truthy と falthy という考え方があります。
truthy な値とは論理演算子に変換したときに true となる値を指し、falthy な値は 変換すると false になる値を指します。
JavaScript において falthy の値は以下のみとなっています。
- 0
- -0
- null
- false
- NaN
- undefined
- "" (空文字)
これ以外は空配列や空オブジェクトであっても全て true と判断されます。数も少ないですし、どれもなんか虚ろな感じがするので覚えられそうですね。
そしてあらゆる値を論理演算子に変換するための簡単な方法として、論理否定演算子 !
を使うことが挙げられます。
console.log(!0); // -> true
console.log(!!0); // -> false
0 は falthy な値ですね。
最初の1行は論理否定演算子を1つだけつけています。つまり 「0の否定を求めてね」 とお願いしているわけです。すると false の反対 = true となります。
次の行では論理否定演算子を2つつけています。つまり 「0の否定の否定を求めてね」 とお願いしているわけです。
すると false の反対の true の反対の false になる、ということで 0 そのものが真偽値としてどう評価されるかが返ってきました!
falthy な値を全て覚え切れなくても、この確かめ方を覚えていれば大丈夫です。
この truthy と falthy ですが、実は以下のような活用方法があります。
function checkArg(arg) {
if(!arg) {
return "invalid!";
}
return "valid";
}
関数の引数チェックですね。
null
や false
、0などをあえて引数として取る関数でなければ、falthy な値を全て弾いてしまうことで想定外の引数をある程度は拒否することができます。
まとめ
型変換はうっかり起こってしまうと想定しない動きの原因になりますが、あえてこちらから使いこなすこともできます。
あなたも今日から「 console.log(('b'+'a'+ + 'a' + 'a').toLowerCase())
ってやると banana🍌 になるんだぜ」とドヤ顔してみませんか?