◆ いろいろな方法でキャストします

コード

以下のコードを実行します
"0xa" とかNaN とか Infinity とか "123abc" とかキャストでどうなるのか怪しそうなのを Boolean, Number, parseInt, +, ~~, !! などでキャストします
var targets = [
true,
false,
0,
-0,
1,
-3,
1.2,
-1.2,
"0",
"-0",
"1",
"-3",
"1.2",
"-1.2",
"",
"abc",
"abc123",
"123abc",
"1e1",
"0xa",
"0b1",
"0777",
"false",
"true",
"null",
"undefined",
null,
undefined,
NaN,
Infinity,
-Infinity,
{},
{a:0},
[],
[1],
[0],
[3,4],
function(){},
new Boolean(true),
new Boolean(false),
new Number(0),
new Number(-0),
new Number(100),
new Number(1.23),
new Number(-1.23),
new Number(NaN),
new Number(Infinity),
new Number(-Infinity),
new String(""),
new String("0"),
new String("-0"),
new String("abc"),
new String("123"),
]

var converter = [
function boolean(x){
console.log(x, Boolean(x))
},
function not_op(x){
console.log(x, !x)
},
function notnot_op(x){
console.log(x, !!x)
},
function number(x){
console.log(x, Number(x))
},
function parsefloat(x){
console.log(x, parseFloat(x))
},
function plus(x){
console.log(x, +x)
},
function minusminus(x){
console.log(x, - -x)
},
function parseint(x){
console.log(x, parseInt(x))
},
function mathfloor(x){
console.log(x, Math.floor(x))
},
function bitreverse_bitreverse(x){
console.log(x, ~~x)
},
]

converter.forEach(function(fn){
console.log(fn.name, "=============")
targets.forEach(fn)
})

結果

Boolean(val)

真偽値変換です
数字は「0」だけ 文字列は空文字だけが false です
あとは null, undefined, NaN の特殊な値が false です
それ以外は全部 true になります
"true""false" "0" も関係ないです

数値や文字列などのプリミティブ値のオブジェクト版も「オブジェクト」なので中身は問わずに true です
new Boolean(false) でも true です

わかりやすいです
truetrue
falsefalse
0false
-0false
1true
-3true
1.2true
-1.2true
"0"true
"-0"true
"1"true
"-3"true
"1.2"true
"-1.2"true
""false
"abc"true
"abc123"true
"123abc"true
"1e1"true
"0xa"true
"0b1"true
"0777"true
"false"true
"true"true
"null"true
"undefined"true
nullfalse
undefinedfalse
NaNfalse
Infinitytrue
-Infinitytrue
{}true
{a:0}true
[]true
[1]true
[0]true
[3,4]true
function(){}true
new Boolean(true)true
new Boolean(false)true
new Number(0)true
new Number(-0)true
new Number(100)true
new Number(1.23)true
new Number(-1.23)true
new Number(NaN)true
new Number(Infinity)true
new Number(-Infinity)true
new String("")true
new String("0")true
new String("-0")true
new String("abc")true
new String("123")true

!val

Boolean関数を通して true/false を反転させたものになります
truefalse
falsetrue
0true
-0true
1false
-3false
1.2false
-1.2false
"0"false
"-0"false
"1"false
"-3"false
"1.2"false
"-1.2"false
""true
"abc"false
"abc123"false
"123abc"false
"1e1"false
"0xa"false
"0b1"false
"0777"false
"false"false
"true"false
"null"false
"undefined"false
nulltrue
undefinedtrue
NaNtrue
Infinityfalse
-Infinityfalse
{}false
{a:0}false
[]false
[1]false
[0]false
[3,4]false
function(){}false
new Boolean(true)false
new Boolean(false)false
new Number(0)false
new Number(-0)false
new Number(100)false
new Number(1.23)false
new Number(-1.23)false
new Number(NaN)false
new Number(Infinity)false
new Number(-Infinity)false
new String("")false
new String("0")false
new String("-0")false
new String("abc")false
new String("123")false

!!val

!val をさらに反転させているので Boolean関数通したのと同じ値になります
truetrue
falsefalse
0false
-0false
1true
-3true
1.2true
-1.2true
"0"true
"-0"true
"1"true
"-3"true
"1.2"true
"-1.2"true
""false
"abc"true
"abc123"true
"123abc"true
"1e1"true
"0xa"true
"0b1"true
"0777"true
"false"true
"true"true
"null"true
"undefined"true
nullfalse
undefinedfalse
NaNfalse
Infinitytrue
-Infinitytrue
{}true
{a:0}true
[]true
[1]true
[0]true
[3,4]true
function(){}true
new Boolean(true)true
new Boolean(false)true
new Number(0)true
new Number(-0)true
new Number(100)true
new Number(1.23)true
new Number(-1.23)true
new Number(NaN)true
new Number(Infinity)true
new Number(-Infinity)true
new String("")true
new String("0")true
new String("-0")true
new String("abc")true
new String("123")true

Number(val)

数値に変換します

"abc" など数値として不正なのは NaN になります
"abc123" "123abc" のように不正な文字列が部分的に入っていても NaN です

16進数や2進数表記も対応していますが 8進数やややこしくなるからか最初の0はないものとされてます
配列ではtoStringが適用された文字列を数値化するので "3,4" となる [3,4]NaNです

null 0 で undefined  NaN というところが覚えにくいです

数値化では プリミティブ値のオブジェクト版はプリミティブ値を使って変換されています
true1
false0
00
-0-0
11
-3-3
1.21.2
-1.2-1.2
"0"0
"-0"-0
"1"1
"-3"-3
"1.2"1.2
"-1.2"-1.2
""0
"abc"NaN
"abc123"NaN
"123abc"NaN
"1e1"10
"0xa"10
"0b1"1
"0777"777
"false"NaN
"true"NaN
"null"NaN
"undefined"NaN
null0
undefinedNaN
NaNNaN
InfinityInfinity
-Infinity-Infinity
{}NaN
{a:0}NaN
[]0
[1]1
[0]0
[3,4]NaN
function(){}NaN
new Boolean(true)1
new Boolean(false)0
new Number(0)0
new Number(-0)-0
new Number(100)100
new Number(1.23)1.23
new Number(-1.23)-1.23
new Number(NaN)NaN
new Number(Infinity)Infinity
new Number(-Infinity)-Infinity
new String("")0
new String("0")0
new String("-0")-0
new String("abc")NaN
new String("123")123

parseFloat(val)

parseFloatNumberと違うところがいくつかあります

"123abc"123になるように前から順に見て非数値になるまでの数値を取り出して数値化します
そのためか "0xa""0b1" が になります

true, false, "", null, undefined 全部 NaN になります

-0 "-0" で結果が変わっています
trueNaN
falseNaN
00
-00
11
-3-3
1.21.2
-1.2-1.2
"0"0
"-0"-0
"1"1
"-3"-3
"1.2"1.2
"-1.2"-1.2
""NaN
"abc"NaN
"abc123"NaN
"123abc"123
"1e1"10
"0xa"0
"0b1"0
"0777"777
"false"NaN
"true"NaN
"null"NaN
"undefined"NaN
nullNaN
undefinedNaN
NaNNaN
InfinityInfinity
-Infinity-Infinity
{}NaN
{a:0}NaN
[]NaN
[1]1
[0]0
[3,4]3
function(){}NaN
new Boolean(true)NaN
new Boolean(false)NaN
new Number(0)0
new Number(-0)0
new Number(100)100
new Number(1.23)1.23
new Number(-1.23)-1.23
new Number(NaN)NaN
new Number(Infinity)Infinity
new Number(-Infinity)-Infinity
new String("")NaN
new String("0")0
new String("-0")-0
new String("abc")NaN
new String("123")123

+val

パースするんじゃなくて 数値にキャストするわけなのでNumber関数使ったのと一緒です
Numberの構文糖衣 ということですね
true1
false0
00
-0-0
11
-3-3
1.21.2
-1.2-1.2
"0"0
"-0"-0
"1"1
"-3"-3
"1.2"1.2
"-1.2"-1.2
""0
"abc"NaN
"abc123"NaN
"123abc"NaN
"1e1"10
"0xa"10
"0b1"1
"0777"777
"false"NaN
"true"NaN
"null"NaN
"undefined"NaN
null0
undefinedNaN
NaNNaN
InfinityInfinity
-Infinity-Infinity
{}NaN
{a:0}NaN
[]0
[1]1
[0]0
[3,4]NaN
function(){}NaN
new Boolean(true)1
new Boolean(false)0
new Number(0)0
new Number(-0)-0
new Number(100)100
new Number(1.23)1.23
new Number(-1.23)-1.23
new Number(NaN)NaN
new Number(Infinity)Infinity
new Number(-Infinity)-Infinity
new String("")0
new String("0")0
new String("-0")-0
new String("abc")NaN
new String("123")123

- -val

マイナス2つでも +val や Number と一緒になります
!! と同じ感じですが マイナス記号の間にスペースがないとデクリメントになってしまうので正しく動かないかエラーになります
true1
false0
00
-0-0
11
-3-3
1.21.2
-1.2-1.2
"0"0
"-0"-0
"1"1
"-3"-3
"1.2"1.2
"-1.2"-1.2
""0
"abc"NaN
"abc123"NaN
"123abc"NaN
"1e1"10
"0xa"10
"0b1"1
"0777"777
"false"NaN
"true"NaN
"null"NaN
"undefined"NaN
null0
undefinedNaN
NaNNaN
InfinityInfinity
-Infinity-Infinity
{}NaN
{a:0}NaN
[]0
[1]1
[0]0
[3,4]NaN
function(){}NaN
new Boolean(true)1
new Boolean(false)0
new Number(0)0
new Number(-0)-0
new Number(100)100
new Number(1.23)1.23
new Number(-1.23)-1.23
new Number(NaN)NaN
new Number(Infinity)Infinity
new Number(-Infinity)-Infinity
new String("")0
new String("0")0
new String("-0")-0
new String("abc")NaN
new String("123")123

parseInt(val)

parseFloat したものから小数点以下切り捨てかとおもいきや 意外な違いがあります
"1e1" "0xa" が違うのは予想外です

Infinity もプラスマイナスどっちのも NaN になります
言われてみると Infinity って int に収まってないですね
trueNaN
falseNaN
00
-00
11
-3-3
1.21
-1.2-1
"0"0
"-0"-0
"1"1
"-3"-3
"1.2"1
"-1.2"-1
""NaN
"abc"NaN
"abc123"NaN
"123abc"123
"1e1"1
"0xa"10
"0b1"0
"0777"777
"false"NaN
"true"NaN
"null"NaN
"undefined"NaN
nullNaN
undefinedNaN
NaNNaN
InfinityNaN
-InfinityNaN
{}NaN
{a:0}NaN
[]NaN
[1]1
[0]0
[3,4]3
function(){}NaN
new Boolean(true)NaN
new Boolean(false)NaN
new Number(0)0
new Number(-0)0
new Number(100)100
new Number(1.23)1
new Number(-1.23)-1
new Number(NaN)NaN
new Number(Infinity)NaN
new Number(-Infinity)NaN
new String("")NaN
new String("0")0
new String("-0")-0
new String("abc")NaN
new String("123")123

Math.floor(val)

parseInt と同じように思うかもですが Number で数値キャストしたあとに小数の処理を行うので Number とほとんど一緒になります
true1
false0
00
-0-0
11
-3-3
1.21
-1.2-2
"0"0
"-0"-0
"1"1
"-3"-3
"1.2"1
"-1.2"-2
""0
"abc"NaN
"abc123"NaN
"123abc"NaN
"1e1"10
"0xa"10
"0b1"1
"0777"777
"false"NaN
"true"NaN
"null"NaN
"undefined"NaN
null0
undefinedNaN
NaNNaN
InfinityInfinity
-Infinity-Infinity
{}NaN
{a:0}NaN
[]0
[1]1
[0]0
[3,4]NaN
function(){}NaN
new Boolean(true)1
new Boolean(false)0
new Number(0)0
new Number(-0)-0
new Number(100)100
new Number(1.23)1
new Number(-1.23)-2
new Number(NaN)NaN
new Number(Infinity)Infinity
new Number(-Infinity)-Infinity
new String("")0
new String("0")0
new String("-0")-0
new String("abc")NaN
new String("123")123

~~val

parseInt から NaN を消したような感じですが これも Number で数値キャストしたあとにビット反転を2回しているので独特な結果です
Infinity -Infinity 0 です
true1
false0
00
-00
11
-3-3
1.21
-1.2-1
"0"0
"-0"0
"1"1
"-3"-3
"1.2"1
"-1.2"-1
""0
"abc"0
"abc123"0
"123abc"0
"1e1"10
"0xa"10
"0b1"1
"0777"777
"false"0
"true"0
"null"0
"undefined"0
null0
undefined0
NaN0
Infinity0
-Infinity0
{}0
{a:0}0
[]0
[1]1
[0]0
[3,4]0
function(){}0
new Boolean(true)1
new Boolean(false)0
new Number(0)0
new Number(-0)0
new Number(100)100
new Number(1.23)1
new Number(-1.23)-1
new Number(NaN)0
new Number(Infinity)0
new Number(-Infinity)0
new String("")0
new String("0")0
new String("-0")0
new String("abc")0
new String("123")123

気になる所

parseIntとMath.floorって数値でも違う

一緒と思っている人が多そうですが 数値に対して行っても違いがあります
parseInt は小数点以下を消します
単純にバックスペース押して消す感じで1の位は変更しません

ですがMath.floorは数値的に小さくします
なので負の数だと1の位が変化します

こんな感じです

int-floor

Numberとparse系関数

近いですが異なる動きをします
parseの2関数でも動きが違うところがあるので parseInt(parseFloat(val)) parseInt(val) で結果が変わってくることもあります

たぶんですが
"1e1" は 「1.0*10」 なので最初の 1 のところまでしかパースされてないんだと思います
"0xa" は int 型を表す16進数表記 ということで parseInt のほうでしか 10 にならないんだと思います


演算子キャストで数値にするときはNumber

数値のコンストラクタに当たる関数ですし当然といえば当然ですね
楽にかくために +val とかよく使うと思いますが parseFloat じゃなくて Number なので動きの違いを覚えておいたほうがよさそうです
長くなってきて +val だと可読性が落ちるから parseFloat にしたら動き変わってる! とか起きないようにね

~~が意外と使えそう

JavaScriptのクイズで制限あるなかでキャストするとき思い出すくらいのダブルチルダキャスト
ビット反転なので NaN にならない特徴があります

+ でキャストすると NaN になってしまうせいでめんどうな分岐処理を追加することはたまにあります
~~ を使うと NaN が になってくれるので使い道がアリそうです


0と-0

JavaScriptではこの2つはなぜか別物になっています
Numberではマイナスがあるものはそのままですが parse系ではただの 0 になってしまいます
ただし 文字列の "-0" だとparse系でも -0 になります

どっちでも計算すると 基本的に同じ値になるのであまり気にしないかと思います
(-0).toString() "0" ですし ↓くらいしか違って困る例がなさそうです
1 / 0 // Infinity
1 / -0 // -Infinity
-1 / -0 // Infinity

プリミティブ値のオブジェクト版

new Number(10) などです
Number String が適用された結果がオブジェクト状態になっています
new Number("xyz") としても NaN が入ったオブジェクトになるだけです

数値化のときはプリミティブ値が使われて オブジェクトでない時と同じ動きです
ですが Boolean値に変換するときはすべてtrueになります

比較用

比較するのに見やすくないので数値への変換部分を比較用にまとめました
NumberparseFloatparseIntMath.floor~~
true1NaNNaN11
false0NaNNaN00
000000
-0-000-00
111111
-3-3-3-3-3-3
1.21.21.2111
-1.2-1.2-1.2-1-2-1
"0"00000
"-0"-0-0-0-00
"1"11111
"-3"-3-3-3-3-3
"1.2"1.21.2111
"-1.2"-1.2-1.2-1-2-1
""0NaNNaN00
"abc"NaNNaNNaNNaN0
"abc123"NaNNaNNaNNaN0
"123abc"NaN123123NaN0
"1e1"101011010
"0xa"100101010
"0b1"10011
"0777"777777777777777
"false"NaNNaNNaNNaN0
"true"NaNNaNNaNNaN0
"null"NaNNaNNaNNaN0
"undefined"NaNNaNNaNNaN0
null0NaNNaN00
undefinedNaNNaNNaNNaN0
NaNNaNNaNNaNNaN0
InfinityInfinityInfinityNaNInfinity0
-Infinity-Infinity-InfinityNaN-Infinity0
{}NaNNaNNaNNaN0
{a:0}NaNNaNNaNNaN0
[]0NaNNaN00
[1]11111
[0]00000
[3,4]NaN33NaN0
function(){}NaNNaNNaNNaN0
new Boolean(true)1NaNNaN11
new Boolean(false)0NaNNaN00
new Number(0)00000
new Number(-0)-000-00
new Number(100)100100100100100
new Number(1.23)1.231.23111
new Number(-1.23)-1.23-1.23-1-2-1
new Number(NaN)NaNNaNNaNNaN0
new Number(Infinity)InfinityInfinityNaNInfinity0
new Number(-Infinity)-Infinity-InfinityNaN-Infinity0
new String("")0NaNNaN00
new String("0")00000
new String("-0")-0-0-0-00
new String("abc")NaNNaNNaNNaN0
new String("123")123123123123123


【追加】
+ プリミティブ値のオブジェクト・-0・funciton 追加
~~ キャストは 32 ビットを超えると parseInt などと動きが変わります