JavaScript 类型转换
| 值 | 字符串 | 数字 | 布尔值 |
|---|---|---|---|
| undefined | "undefined" | NaN | false |
| null | "null" | 0 | false |
| true | "true" | 1 | |
| false | "false" | 0 | |
| "" | 0 | false | |
| "1.2" | 1.2 | true | |
| "one" | NaN | true | |
| 0 | "0" | false | |
| -0 | "0" | false | |
| NaN | "NaN" | false | |
| Infinity | "Infinity" | true | |
| -Infinity | "-Infinity" | true | |
| 1 | "1" | true | |
| {} | "[object Object]" | NaN | true |
| [] | "" | 0 | true |
| [9] | "9" | 9 | true |
| [1, 2, 3] | "1,2,3" | NaN | true |
| ['a'] | "a" | NaN | true |
| function foo(){} | "function foo(){}" | NaN | true |
类型转换的基本规则
- ToString
- ToNumber
- ToBoolean
- ToPrimitive
ToString
负责非字符串到字符串的强制类型转换。
基本数据类型
null=>"null"undefined=>"undefined"true=>"true"12=>"12"
对象
除非自行定义,否则 toString() 返回内部属性 [[Class]] 的值。
这个属性无法直接访问,一般通过 Object.prototype.toString(..) 查看
如果对象有自己的 toString() 方法,字符串化时就会调用该方法并使用其返回值。
var a = {
name: 'ym'
}
var b = {
name: 'ym',
toString: function() {
return this.name;
}
}
a.toString(); // "[object Object]"
b.toString(); // "ym"
数组
数组的默认 toString() 方法经过重新定义
var a = [1, 2, 3];
a.toString(); // "1,2,3"
ToNumber
基本数据类型
true=> 1false=> 0undefined=>NaNnull=> 0
对象(包括数组)
首先会被转换为相应的基本类型值。如果是非数字的基本类型值,则按上面的规则强制转换。
将值转换为相应基本类型的步骤:(ToPrimitive)
- 检查该值是否有
valueOf()方法。- 如果有并且返回基本类型值,就使用该值进行强制类型转换。
- 如果没有就使用
toString()的返回值进行强制转换。
- 如果
valueOf()和toString()均不返回基本类型值,会产生TypeError错误。
// case1: 对象只有 valueOf 方法,并且返回基本类型值
// 此时就调用 valueOf
var a = {
valueOf: function() {
return '42';
}
}
// case2: 对象只有 toString 方法,并且返回基本类型值
// 此时调用 toString
var b = {
toString: function() {
return '32';
}
}
// case3:两种方法都有。并且 valueOf 返回基本类型值
// 此时调用 valueOf
var c = {
valueOf: function() {
return '42';
},
toString: function() {
return '32'
}
}
// case4: 两种方法都有。但是 valueOf 返回的不是基本类型值,而 toString 返回基本类型值
// 此时调用 toString
var d = {
valueOf: function() {
return [1, 2];
},
toString: function() {
return '32'
}
}
// case5: 两种方法都有。但是返回的都不是基本类型值
// 此时报错 Uncaught TypeError: Cannot convert object to primitive value
var e = {
valueOf: function() {
return [1, 2];
},
toString: function() {
return [1, 3];
}
}
Number(a); // 42
Number(b); // 32
Number(c); // 42
Number(d); // 32
Number(e); // Uncaught TypeError: Cannot convert object to primitive value
栗子:chestnut:
// [].valueOf() => []
// [].toString() => ""
// "" => 0
Number([]); // 0
// ['abc'].valueOf() => ['abc']
// ['abc'].toString() => "abc"
// "abc" => NaN
Number(['abc']); // NaN
ToBoolean
两类值
-
可以被强制转换为
false的值(注意这一部分的值比较少)undefinednullfalse+0-0NaN""
注意1:
[]和{}强制转换并不是 false 而是 true注意2:
var a = new Boolean(false); var b = new Number(0); var c = new String(""); Boolean(a && b && c) // 三者强制转换均为 true,因为本质是对象 -
其他(转换为
true)
== 号的比较
两个值的类型相同
这种情况就只比较值是否相等,不会做类型转换。
正常情况
1 == 1 // true
'abc' == 'abc' // true
true == true // true
null == null // true
undefined == undefined // true
[] == [] // false
{} == {} //false
特别情况
NaN == NaN // false
+0 == -0 // true
两个值的类型不同
这种情况会发生隐式类型转换。会将其中之一或者二者都转换为相同的类型后再进行比较。
数字和字符串
不论二者的位置关系是怎么样,就是将字符串转换为数字类型
- a 是数字,b 是字符串,返回 a == ToNumber(b)
- a 是字符串,b 是数字,返回 ToNumber(a) == b
// case1: 数字 == 字符串
42 == '42' // true
42 === '42' // false
// case2: 字符串 == 数字
'42' == 42 // true
布尔和其他类型
-
布尔类型首先会转换成数字类型。(同样跟位置没有关系)
=> 因此问题变成了数字和其他类型的比较了
// case1:布尔 == 字符串
// 第一步:true => 1
// 第二步:'42' => 42
// 第三步:1 == 42 => false
true == '42' // false
false == '42' // false
// case2:布尔 == 数字
true == 1 // true
false == 0 // true
null 和 undefined
不论位置,结果为 true。
null == undefined // true
undefined == null //true
null 和 undefined 与其他类型
均返回 false。
null == false // false
undefined == false // false
null == "" // false
undefined == "" // false
null == 0 // false
undefined == 0 // false
对象和非对象
对象首先要转化为基本数据类型
- a 是对象,b 是非对象,返回 a == ToPrimitive(b)
- a 是非对象,b 是对象,返回 ToPrimitive(a) == b
// case1
// 第一步:[42] => '42'
// 第二步:'42' => 42
// 第三步:42 == 42 => true
42 == [42] // true
// case2:布尔和数组
// false => 0
// [] => ""
// "" => 0
[] == false // true
// ![] => false
![] == false // true
'abc' == new String('abc') // true
123 == new Number(123) // true
false == new Boolean(false) // true
null == Object(null) // false
undefined == Object(undefined) // false
NaN == new Number(NaN) // false
数组与其他
数组会转换为字符串,因此问题就变成了字符串与其他的比较
[] == false // true
[] == "" // true
[] == 0 // true
// ToBoolean(![]) => false
// [] == false => true
[] == ![] // true
// 因为先进行 !运算,所以 false 不会首先转换为数字
// 第一步:![] => false
// 第二步:false == false => true
![] == false // true
注意!:由于 !的优先级要高于 ==,因此会先进行 !运算,再进入 == 流程
+ 号的隐式转换
数字和字符串运算
两种情况
- 字符串 + 数字 => 字符串
- 数字 + 字符串 => 字符串
总结
字符串和数字存在加法运算,最终得到字符串。
加号和字符串
+ 数字字符串 => 数字+ 非数字字符串 => NaN
参考
-
《你不知道的JS》
-
《JavaScript 权威指南》