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 權威指南》