JS型別轉換總結
前言
JS 令人頭疼的一點就是它屬於弱型別語言,一個變數儲存的值可以是字串、數值、布林值或者物件等,可以隨時變更。獲取一個變數,你不會知道其儲存的值是什麼型別的,所以很多時候都需要進行型別檢測。
除了手動變更型別之外,有些情況下,JS 內部也會自動進行型別轉換,以滿足部分操作符以及語句等的執行。
下面就是我對 JS 型別轉換的一些總結,其中大部分來自《JavaScript 高階程式設計》這本書。
1. Boolean 轉換
轉換情況
- 呼叫
Boolean()
- 在
if
或while
流程控制中,內部執行相應的Boolean()
轉換 - 邏輯運算子,主要是
!
和!!
,內部執行Boolean()
轉換規則
資料型別 | 轉換為 true 的值 |
轉換為 false 的值 |
---|---|---|
String | 任何非空字串 | 空字串"" |
Number | 任何非零數字值(包括無窮大) | 0 和 NaN |
Object | 任何物件 | null |
Undefined | 不適用 | undefined |
也就是說,只有 0 / NaN / "" / null / undefined
才會轉換為 false
,其餘都是 true
所以在 if
判斷中,直接寫變數有時候是不夠嚴謹的
if (!a){
//=> 想要在 a 不存在或沒定義的時候執行
//=> 實際上儲存的值是 0 或者 '' 等也會執行
}
//=> 應該使用 typeof
if (typeof a == 'undefined') {
//=> a 不存在或沒定義的時候執行
}
//=> 或者使用全等
if (a === undefined) {
//=> 使用 == 也不夠嚴謹,因為 null == undefined
//=> 需要區分 null 或 undefined 的 情況較少
}
2. Number 轉換
轉換情況
- 呼叫
Number()
、parseInt()
、parseFloat()
- 其他情況都是使用
Number()
isNaN()
- 一元加或減操作符,注意:這裡是一元的,如
s = + s
,區別於加法和拼接 - 遞增或遞減,以及加法(除了拼接)、減法、乘法、除法、求模等操作符
- 關係操作符
轉換規則
Number()
:
- Boolean 值
- true
=> 1
- false
=> 0
null
=>0
undefined
=>NaN
String 值
- 只包含數字(包含正負號),將其轉換為十進位制數值,忽略前導零
- 包含有效的浮點格式,將其轉換為對應的浮點數值,忽略前導零
- 包含有效的十六進位制格式,將其轉換為相同大小的十進位制數值
- 空字串
""
,空格' '
,換行符'\n'
,製表符'\t'
=>'0'
- 包含其他格式的字串,則將其轉換為
NaN
Object 值
- 呼叫物件的
toString()
方法,然後依照上面的規則轉換返回的字串
- 呼叫物件的
// [普通物件]
({}).toString() => '[object Object]' => NaN
// [陣列]
[12,23].toString() => '12, 23' => NaN
[12].toString() => '12' => 12
[].toString() => '' => 0
// [正則]
/^$/.toString() => '/^$/' => NaN
// [函式]
function a() {}
a.toString() => "function a(){}" => NaN
parseInt()
:
- 第一個引數必須是字串,如果不是則轉換為字串,使用 toString()
方法轉換為字串
- 忽略前面的空格,直至找到第一個非空字元
- 第一個非空字元不是數字字元或者負號,則返回 NaN
- 空字串返回 NaN
- 第一個是數字字元,會繼續解析下一個字元,直至遇到非數字字元,返回前面的數字字元
- 遇到非數字字元後,後面的字元都是無效的了
- 傳入第二個引數:轉換時使用的基數,即多少進位制,就可以解析二進位制、八進位制、十六進位制的字串。指定了第二個引數的,字串中甚至不用帶前面的字首,如 parseInt("AF", 16);//175
- 為了避免解析錯誤,任何情況下都應該明確指定基數,十進位制也不例外
parseFloat()
:
- 第一個引數必須是字串,如果不是則轉換為字串,使用 String()
方法
- 字串中第一個小數點有效,第二個無效
- 空字串返回 NaN
- 始終忽略前導零
- 只要遇到非浮點字元或者第二個小數點,後面的字串都無效
- 字串解析為整數,那麼返回整數
3. String 轉換
轉換情況
- 基於
alert / confirm / prompt / document.write
等方法輸出內容 - 呼叫
toString()
、String()
- 加號操作符,有一個是字串時,內部呼叫
toString()
- 物件轉換成 Number 型別時,內部呼叫
toString()
轉換規則
toString()
方法
- 返回相應值的字串表現
- 數值、布林值、物件和字串值都有一個 toString()
方法
- 字串的 toString()
方法返回字串的一個副本
- null
=> "null"
- undefined
=> "undefined"
- NaN
=> 'NaN'
- true
=> 'true'
,false
=> 'false'
- 普通物件只能返回 [object Object]
,不能返回字串形式
- 陣列 []
=> ''
,[12, 23]
=> '12,23'
- 正則、日期等物件都返回其字串表現
String()
轉型函式,你可以認為 String
和 toString
轉換機制是一樣的。
4. 特殊轉換
+ 號操作的特殊情況
// 雖然沒有看到字串,但是引用型別轉換為數字時,會先轉換為字串,這樣就變成了字串拼接
[12] + 10 //=> "1210"
({}) + 10 //=> '[object Object]10'
{} + 10 //=> 10
//=> 原因是 {} 會被解析為程式碼塊,最後只是操作了 +10
{} + {} //=> '[object Object][object Object]'
//=> 非常特殊,不同瀏覽器解析有差異
({})+{} //=> '[object Object][object Object]'
{} + ({}) //=> NaN
//=> 一行中開頭的 {} 才會被解析為程式碼塊,所以用 () 包裹後可以避免被解析為程式碼塊,一行後面的 {} 不會被解析為程式碼塊,而是空物件。
== 進行比較時
物件 == 物件:地址相等才相等
{} == {} //=> false
[] == [] //=>false
{name: 'xxx'} == {name: 'xxx'} //=> false
var obj1 = {};
var obj2 = obj1;
obj1 == obj2 //=> true
物件 == 數字:把物件轉換為數字
物件 == 布林:都轉化為數字
字串 == 數字:把字串轉換為數字
字串 == 布林:都轉化為數字
布林 == 數字:把布林轉換為數字
物件 == 字串:把物件轉換為字串之後再比較
1==true //=> true
1==false //=> false
2==true //=> false,都轉化為數字
[]==false //=> true,都轉換為數字
[]==true //=> false,都轉換為數字
![]==false //=> true,先算 ![] 為 false,再比較
![]==true //=> false,先算 ![] 為 false,再比較
[]==![] //=> true,先算 ![] 為 false,然後都轉換為數字再比較