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
=>NaN
null
=> 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
的值(注意这一部分的值比较少)undefined
null
false
+0
-0
NaN
""
注意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 权威指南》