JavaScript是一種動態(tài)類型語言,變量沒有類型限制,可以隨時賦予任意值,而在參與運(yùn)算的時候,內(nèi)部會進(jìn)行一系列的轉(zhuǎn)換,所以,我們需要搞清楚這些類型之間的轉(zhuǎn)換規(guī)則,避免出現(xiàn)未預(yù)知的bug。
強(qiáng)制轉(zhuǎn)換
強(qiáng)制轉(zhuǎn)換主要使用Number、String和Boolean三個構(gòu)造函數(shù),手動將各種類型的值轉(zhuǎn)換為數(shù)字、字符串或者布爾值。
Number函數(shù),轉(zhuǎn)換為數(shù)值
Number函數(shù)可以將任意類型的值轉(zhuǎn)換成數(shù)值,Number函數(shù)接受的參數(shù)可以分兩種情況來看待:原始類型,對象。
原始類型的值
原始類型的值主要是字符串、布爾值、undefined和null,它們都能被Number轉(zhuǎn)化成數(shù)值或NaN。
// 數(shù)值:轉(zhuǎn)換后還是原來的值
Number(111) // 111
// 字符串:如果可以被解析為數(shù)值,則轉(zhuǎn)換為對應(yīng)的數(shù)值
Number('223') //223
// 字符串:如果不可以被解析為數(shù)值,返回NaN
Number('233dfsa')// NaN
// 空字符串轉(zhuǎn)換為0
Number('')// 0
// 布爾值true轉(zhuǎn)換為1,false轉(zhuǎn)換為0
Number(true)// 1
Number(false) // 0
Number(undefined) // NaN
Number(null) // 0
Number函數(shù)相對于parseInt函數(shù)嚴(yán)格點(diǎn),只要有一個字符無法轉(zhuǎn)化為數(shù)值,整個字符串就返回NaN。
Number('324 34243')// NaN
parseInt('324 34243')// 324
parseInt逐個解析字符,而Number函數(shù)整體轉(zhuǎn)換字符串類型,他們都會過濾字符串的前導(dǎo)和后綴字符。
對象的轉(zhuǎn)換規(guī)則
當(dāng)Number函數(shù)的參數(shù)是對象時,將返回NaN,除非是包含單個數(shù)值的數(shù)組。
Number({a: 1}) // NaN
Number([1, 2, 3]) // NaN
Number([5]) // 5
Number方法轉(zhuǎn)換對象的規(guī)則:
- 調(diào)用對象自身的valueOf方法,如果返回原始類型的值,則直接對該值使用Number函數(shù)。
- 如果valueOf方法返回的還是對象,則改為調(diào)用對象自身的toString方法。如果返回原始類型的值,則對該值使用Number函數(shù)。
- 如果toString方法返回的是對象,就報錯。
var arr = [1, 2, 3, 4];
arr.toString()// '1,2,3,4'
Number(arr.toString()) // NaN
String函數(shù),轉(zhuǎn)換為字符串
也可以分為原始類型和對象來分析
原始類型值
轉(zhuǎn)換后都為字符串
String(123) // "123"
String('abc') // "abc"
String(true) // "true"
String(undefined) // "undefined"
String(null) // "null"
對象類型
String方法的參數(shù)如果是對象,返回一個類型字符串
var a = {a: 1};
a.toString(); // "[object Object]"
如果是數(shù)組,返回該數(shù)組的字符串形式。
a = [[3, 3], [2, 3]];
a.toString(); // "3,3,2,3"
String 函數(shù)的規(guī)則:
- 先調(diào)用自身的toString方法,如果返回原始類型的值,則對該值使用String函數(shù)
- 如果toString方法返回的是對象,再調(diào)用原對象的valueOf方法,如果valueOf方法返回原始類型的值,則對該值使用String函數(shù)。
- 如果valueOf方法返回的是對象,就報錯。
Boolean函數(shù),轉(zhuǎn)換為布爾值
除了一下六個值為false,其他的都為true
- undefined
- null
- 0、-0或+0
- NaN
- ‘’(空字符串)
注意: 所有對象(包括空對象)的轉(zhuǎn)化結(jié)果都是true,甚至連false對應(yīng)的布爾對象new Boolean(false)
也是true。
自動轉(zhuǎn)換
自動轉(zhuǎn)換以強(qiáng)制轉(zhuǎn)換為基礎(chǔ),遇到下面三種情況時,JavaScript會自動轉(zhuǎn)換。
- 不同類型的數(shù)據(jù)相互運(yùn)算
- 對非布爾值類型的數(shù)據(jù)求布爾值
- 對非數(shù)值類的數(shù)據(jù)使用一元運(yùn)算符
自動轉(zhuǎn)換的規(guī)則為:預(yù)期什么類型的值,就調(diào)用該類型的轉(zhuǎn)換函數(shù)。比如,如果預(yù)期使用字符串的值,就調(diào)用String函數(shù)轉(zhuǎn)換。如果該位置既可以是字符串,也可以是數(shù)值,就默認(rèn)轉(zhuǎn)換為數(shù)值。
自動轉(zhuǎn)換為布爾值
當(dāng)JavaScript遇到預(yù)期為布爾值的地方(比如if語句的條件部分、非運(yùn)算、三元運(yùn)算符等),就會將非布爾值的參數(shù)自動轉(zhuǎn)換為布爾值,系統(tǒng)自動調(diào)用Boolean函數(shù)。
將一個表達(dá)式轉(zhuǎn)換為布爾值
// 寫法一
expression ? true : false
// 寫法二
!! expression
自動轉(zhuǎn)換為字符串
當(dāng)JavaScript遇到預(yù)期為字符串的地方,就會將非字符串的數(shù)據(jù)自動轉(zhuǎn)換為字符串。系統(tǒng)內(nèi)部會自動調(diào)用String函數(shù)。字符串的自動轉(zhuǎn)換主要發(fā)生在加法運(yùn)算,當(dāng)一個值為字符串,另一個值為非字符串,則后者轉(zhuǎn)換為字符串
這種規(guī)則為字符串+other
'5' + {} // "5[object Object]"
這種規(guī)則為對象+other
{} + '5' // 5
自動轉(zhuǎn)換為數(shù)字
當(dāng)JavaScript遇到預(yù)期為數(shù)值的地方,就會自動將參數(shù)轉(zhuǎn)換為數(shù)值。自動調(diào)用Number函數(shù)。
除了加法運(yùn)算符有可能把運(yùn)算子轉(zhuǎn)換為字符串,其他運(yùn)算符都會把運(yùn)算子自動轉(zhuǎn)換為數(shù)值。
最后
由于自動轉(zhuǎn)換具有不確定性,而且不易除錯,建議在預(yù)期為布爾值、數(shù)值、字符串的地方,全部使用Boolean、Number和String函數(shù)進(jìn)行顯式轉(zhuǎn)換。
參考文獻(xiàn):《JavaScript 標(biāo)準(zhǔn)參考教程(alpha)》,by 阮一峰