JavaScript那些不經意間發(fā)生的數(shù)據(jù)類型自動轉換
JavaScript可以自由的進行數(shù)據(jù)類型轉換,也提供了多種顯式轉換的方式。但是更多的情況下,是由JavaScript自動轉換的,當然這些轉換遵循著一定的規(guī)則,了解數(shù)據(jù)類型自由轉換的規(guī)則是非常必要的。
數(shù)據(jù)類型
聊到數(shù)據(jù)類型轉換,就不得不提到 JavaScript 的數(shù)據(jù)類型:原始類型( Number , String , Boolean , undefined , null , Symbol),對象類型 (Object)。當然Object有可以細分出 Array , Date , RegExp等等對象。
既然分為這么多種數(shù)據(jù)類型,每種數(shù)據(jù)類型肯定會有特定的用途,那么當提供的值的數(shù)據(jù)類型與預期不符時要怎么辦呢?
比如我需要在控制語句中使用到 boolean 值,提供的值卻是 string 。當然我們可以顯式轉換 Boolean( a : string) ,但是根據(jù)日常經驗,我們知道其實不需要這么復雜,可以在控制語句中直接用這個string類型的變量 ,也可以達到預期的效果。如下:

可見自動轉換方便很多,但是在這個過程中到底是按照什么規(guī)則處理的呢?
自動轉換
什么時候會發(fā)生自動轉換?
犀牛書上是這樣描述的: 當JavaScript期望使用一個布爾值的時候,你可以提供任意類型值,JavaScript將根據(jù)需要自行轉換類型。一些值(真值)轉換為true , 一些值(假值)轉換為false 。這在其他類型中同樣適用:如果JavaScript期望使用一個字符串,它把給定的值轉換為字符串。如果JavaScript期望一個數(shù)字,它把給定的值轉換為數(shù)字(如果轉換結果毫無意義的話,將會返回NaN)。
簡而言之就是:JavaScript有一些語句/運算符對數(shù)據(jù)類型有要求,但我們提供的與預期不符時,就會發(fā)生自動類型轉換。
對數(shù)據(jù)類型有期待的表達式和運算符
- 期待boolean類型的:
if、do while、while do、&&、||、!(與或非邏輯表達式) 、? :( 三目運算符) - 期待number類型的 :
+-*/%(算數(shù)運算符) 、++--(增量/減量運算符) 、>>=<<=(數(shù)字比較) - 期待string的:
+(字符串連接) 、>>=<<=(字母排序比較) - 特殊的 :
==、!=(不)相等運算符,在檢測兩個操作數(shù)是否相等時,會進行類型轉換;(注意 :===、!==是(不)嚴格相等運算符,是不會進行類型轉換的)
需要說明的是,1中當然可以傳入表達式,但是表達式返回的結果也肯定會返回boolean類型的值,或者返回值被轉換為boolean;2和3有一些重復的運算符 : + 、 > 、 >= 、 < 、 <= ,這些運算符在不同場景下發(fā)生自動轉換的時候,會有不同的優(yōu)先級。
運算符在不同場景的轉換優(yōu)先級
+
// + 有兩種作用:算數(shù)運算和字符串連接。所以期待的是數(shù)字和字符串!
// 1、兩個操作數(shù)同為數(shù)字,或者同為字符串,不需要進行轉換
1 + 1 // 2
'1' + '1' // '11'
// 2、有一個操作數(shù)是字符串,則另外一個也會轉換為字符串
'1' + 1 // "11"
'1' + null // "1null"
'1' + {} // "1[object Object]"
'1' + new Date() // "1Wed Jun 20 2018 11:49:55 GMT+0800 (中國標準時間)"
// 3、如果有一個操作數(shù)是對象的話,會轉化為原始值(除了Date對象是調用toString()方式轉換 , 其他對象都會調用 valueOf() 進行轉換 , 但是由于多數(shù)對象只是簡單的繼承了valueOf() , 只會返回對象,而不是一個原始值,所以會再調用toString進行轉換) , 所以這里可以簡單的理解為:都會轉換為字符串 。 另一個操作數(shù)也會轉換為字符串
1 + {} // "1[object Object]"
1 + new Date() // "1Wed Jun 20 2018 11:56:56 GMT+0800 (中國標準時間)"
1 + [] // "1"
// 4、 其他情況都會轉換為數(shù)字
1 + null // 1
1 + undefined // NaN從例子中可以看到,+ 的轉換其實是優(yōu)先轉換為字符串的,如果操作數(shù)中又字符串或者對象(對象在這里會轉換為字符串),則會按照 字符串連接進行操作的。從例子的第3個可以看到,第一個操作數(shù)都是數(shù)字,但是會轉化為字符串。例子中的第4個,沒有對象和字符串,null 和 undefined 都轉換為 數(shù)字進行算數(shù)運算,其中 undefined -> number 會返回 NaN , 所以計算結果為 NaN。
+ 還有特殊的用法,就是轉換為數(shù)字,如下。會將 + 后面的操作數(shù)轉換為數(shù)字,具體的轉換規(guī)則后續(xù)會說明。
+ null // 0
+ undefined // NaN
+ {} // NaN
+ new Date() // 1529467646682
+ ["5"] // 5
+ "4" // 4
> 、>= 、< 、<=
> 、>= 、< 、<= 這些比較運算符的規(guī)則和 + 類似,不過是會優(yōu)先轉換為數(shù)字進行比較。
// 作用 : 比較數(shù)值大小或者再字母表中的位置。也是期待數(shù)字和字符串!
1、兩個操作數(shù)中只要有一個不是字符串,則兩個值都轉為數(shù)字
"3" > "11" // true 字符串比較
3 > "11" // false 11 轉換為數(shù)字
true > '0' // true true 和 ‘0' 都轉換為數(shù)字
2、對象同樣會轉換為原始值(不過這里的Date對象也是優(yōu)先調用valueOf ,返回的是毫秒數(shù),其他的和上述 + 的一樣),如果轉換后有一個字不是字符串,則兩個值也都需要轉換為數(shù)字
1000 > new Date() // false
100000000000000000000000 > new Date() // true date對象轉換為數(shù)字
"100000000000000000000000" > new Date() // true 左值也隨著 date對象一起轉換為數(shù)字
'11' > ["3"] // false 數(shù)組轉為字符串,所以這里是字符串比較
這里需要注意的是,只要在轉換為數(shù)字的過程中,有一個值是 NaN ,那么比較的結果肯定是 false。
== 、 !=
== 、 != (不)相等運算符是不嚴格的比較,所以,如果兩個操作數(shù)不是同一類型,那么會嘗試進行一些類型轉換,然后進行比較。有以下規(guī)則和類型轉換:
- 一個值是
undefined,一個值是null,則相等 - 一個值是數(shù)字,一個值是字符串,則字符串轉換為數(shù)字進行比較
true和false會分別轉換為1和0- 一個值是字符串或者數(shù)字,另一個是對象,對象轉換為原始值(
Date類只調用toString,其他的和之前的一致),然后進行比較。 - 其他的比較,全是
false。
null == undefined // true 1 null == 0 // false 5 1 == '1' // true 2 1 == true // true 3 2 == true // false 3 1 == [1] // true 4 '1' == ['1'] // true 4 數(shù)組轉為字符串 1 == ['1'] // true 4 數(shù)組轉為字符串再轉為數(shù)字
對象包裝
還有一種自動轉換也很容易被忽略,但是經常見到。那就是對象包裝。
思考一個問題,為什么數(shù)字是原始類型,卻可以使用 toString 方法? 只有對象才會有方法的,為什么數(shù)字卻可以使用?
let x = 1 x.toString() // "1"
因為在x需要使用方法的時候,JavaScript會通過調用 new Number(x) 的方式將它暫時轉換為對象,它繼承了Number對象的方法,所以就可以調用toString了。同樣的還有字符串、布爾值,也是通過各種的構造函數(shù)進行轉換。這也是為什么undefined和null,不可以使用toString的原因,因為它們沒有構造函數(shù)。
x = null x.toString() //VM289:1 Uncaught TypeError: Cannot read property 'toString' of //null // at <anonymous>:1:3 //(anonymous) @ VM289:1 x = undefined x.toString() //VM305:1 Uncaught TypeError: Cannot read property 'toString' of //undefined // at <anonymous>:1:3
目前我所了解的自動轉換就只有這么多,后續(xù)再繼續(xù)補充。那么自動轉換的過程中,又有哪些規(guī)則呢?
自動轉換規(guī)則
any -> boolean
在其他類型的值轉換為 boolean 時,只有這幾個會轉換為 false ,其他都是 true : undefined 、 null 、 "" 、 0 、-0 、NaN。
Boolean(0) // false
Boolean("") //false
Boolean(NaN) //false
Boolean(undefined) //false
Boolean(null) // false
// 空對象 空數(shù)組 空函數(shù) 都會true
Boolean({}) // true
Boolean([]) //true
Boolean(function () {}) // true
// 此時是一個boolean對象,而不是原始值,所以是true
Boolean(new Boolean(false)) // true
any -> number
在其他類型的值轉換為number是,就復雜一些:
1.boolean -> number
true -> 1
false -> 0
2.string -> number
由數(shù)字組成的字符串,可以直接轉換為數(shù)字,開始和結尾的空格都可以忽略。不符合的字符串會返回NaN。
+'' // 0 空字符串 +'100' // 100 +' 100 ' // 100 忽略前后空格 +' 100aa' // NaN 有其他非數(shù)字
備注:這里的規(guī)則是自動轉換的規(guī)則,如果是顯示轉換的話,構造函數(shù)Number() 和此規(guī)則一致,而window.parseInt() window.parseFloat的解析規(guī)則則不一樣。如下
window.parseInt(' 100a ') // 100
window.parseFloat(' 100.11a') // 100.11
3.對象 -> number
對象會先嘗試調用 valueOf 返回原始值,如果沒有則調用toString返回原始值,再進行轉換返回??磶讉€例子
+new Date() // 1529483712712 date對象的valueOf返回毫米數(shù),即為數(shù)字
+[] // 0 數(shù)組valueOf為它自己,再調用toString 返回 “” ,空字符串轉換為數(shù)字為0
+['1'] // 1 同樣toString 返回 “1” , 轉換為數(shù)字為 1
+['1','2'] // NaN toString 返回 “1,2” 轉換為數(shù)字 NaN
+{} // NaN toString [Object,Object] , 轉換為數(shù)字 NaN4.undefined null
null -> 0
undefined -> NaN
any -> string
1.null undefined boolean number
這幾個原始類型的轉換非常簡單,就是將自身用引號包裹而已。
'' + 1 // "1" '' + true // "true" '' + undefined // "undefined" '' + null // "null"
2.object -> string
和對象轉化為數(shù)字類似,不過是先調用toString,在調用valueOf。
'' + {} // "[object Object]"
'' + [] // ""
'' + [1,2,3] // "1,2,3"
'' + function() {} // "function () {}"
'' + new Date() // "Wed Jun 20 2018 16:50:56 GMT+0800 (中國標準時間)"
可以看出不同的對象差別挺大的,數(shù)組會將每個元素用逗號分開,生成字符串,date對象toString返回的是中國標準時間,從這里就可以看過和轉化成數(shù)字的不同邏輯了,先嘗試 toString 不行才再 valueOf。
總結
自動類型轉換真的非常常見,常用的一些便捷的轉類型的方式,都是依靠自動轉換產生的。比如 轉數(shù)字 + x 、 x - 0 ,轉字符串 : "" + x 等等?,F(xiàn)在總算知道為什么可以這樣便捷轉換。
以上就是JavaScript那些不經意間發(fā)生的數(shù)據(jù)類型自動轉換的詳細內容,更多關于JavaScript數(shù)據(jù)類型轉換的資料請關注腳本之家其它相關文章!
相關文章
ajax提交表單實現(xiàn)網(wǎng)頁無刷新注冊示例
這篇文章主要介紹了ajax提交表單實現(xiàn)網(wǎng)頁無刷新注冊示例,需要的朋友可以參考下2014-05-05

