'2'>'10'==true?解析JS如何進(jìn)行隱式類型轉(zhuǎn)換
前言
'2'>'10'返回的true,可能很多人都不是很能理解吧? 在js中,當(dāng)運(yùn)算符在運(yùn)算時(shí),如果兩邊數(shù)據(jù)不統(tǒng)一,CPU就無法計(jì)算,這時(shí)我們編譯器會(huì)自動(dòng)將運(yùn)算符兩邊的數(shù)據(jù)做一個(gè)數(shù)據(jù)類型轉(zhuǎn)換,轉(zhuǎn)成一樣的數(shù)據(jù)類型再計(jì)算。 這種無需程序員手動(dòng)轉(zhuǎn)換,而由編譯器自動(dòng)轉(zhuǎn)換的方式就稱為隱式轉(zhuǎn)換。
想要知道'2'>'10'為什么是true,我們得先來了解一下JavaScript的隱式類型轉(zhuǎn)換規(guī)則。
隱式類型轉(zhuǎn)換規(guī)則
1. == 操作符的強(qiáng)制類型轉(zhuǎn)換規(guī)則?
- 字符串和數(shù)字之間的相等比較,將字符串轉(zhuǎn)換為數(shù)字之后再進(jìn)行比較。
- 其他類型和布爾類型之間的相等比較,先將布爾值轉(zhuǎn)換為數(shù)字后,再應(yīng)用其他規(guī)則進(jìn)行比較。
- null 和 undefined 之間的相等比較,結(jié)果為真。其他值和它們進(jìn)行比較都返回假值。
- 對象和非對象之間的相等比較,對象先調(diào)用 ToPrimitive 抽象操作后,再進(jìn)行比較。
- 如果一個(gè)操作值為 NaN ,則相等比較返回 false( NaN 本身也不等于 NaN )。
- 如果兩個(gè)操作值都是對象,則比較它們是不是指向同一個(gè)對象。如果兩個(gè)操作數(shù)都指向同一個(gè)對象,則相等操作符返回true,否則,返回 false。
2.遞增遞減操作符(前置與后置)、一元正負(fù)操作符
這些操作符適用于任何數(shù)據(jù)類型的值,針對不同類型的值,該操作符遵循以下規(guī)則(經(jīng)過對比發(fā)現(xiàn),其規(guī)則與Number()規(guī)則基本相同):
- 如果是包含有效數(shù)字字符的字符串,先將其轉(zhuǎn)換為數(shù)字值(轉(zhuǎn)換規(guī)則同Number()),在執(zhí)行加減1的操作,字符串變量變?yōu)閿?shù)值變量。
- 如果是不包含有效數(shù)字字符的字符串,將變量的值設(shè)置為NaN,字符串變量變成數(shù)值變量。
- 如果是布爾值false,先將其轉(zhuǎn)換為0再執(zhí)行加減1的操作,布爾值變量編程數(shù)值變量。
- 如果是布爾值true,先將其轉(zhuǎn)換為1再執(zhí)行加減1的操作,布爾值變量變成數(shù)值變量。
- 如果是浮點(diǎn)數(shù)值,執(zhí)行加減1的操作。
- 如果是對象,先調(diào)用對象的valueOf()方法,然后對該返回值應(yīng)用前面的規(guī)則。如果結(jié)果是NaN,則調(diào)用toString()方法后再應(yīng)用前面的規(guī)則。對象變量變成數(shù)值變量。
3.加法運(yùn)算操作符
加號(hào)運(yùn)算操作符在Javascript也用于字符串連接符,所以加號(hào)操作符的規(guī)則分兩種情況:
如果兩個(gè)操作值都是數(shù)值,其規(guī)則為:
- 如果一個(gè)操作數(shù)為NaN,則結(jié)果為NaN
- 如果是Infinity+Infinity,結(jié)果是Infinity
- 如果是-Infinity+(-Infinity),結(jié)果是-Infinity
- 如果是Infinity+(-Infinity),結(jié)果是NaN
- 如果是+0+(+0),結(jié)果為+0
- 如果是(-0)+(-0),結(jié)果為-0
- 如果是(+0)+(-0),結(jié)果為+0
如果有一個(gè)操作值為字符串,則:
- 如果兩個(gè)操作值都是字符串,則將它們拼接起來
- 如果只有一個(gè)操作值為字符串,則將另外操作值轉(zhuǎn)換為字符串,然后拼接起來
- 如果一個(gè)操作數(shù)是對象、數(shù)值或者布爾值,則調(diào)用toString()方法取得字符串值,然后再應(yīng)用前面的字符串規(guī)則。對于undefined和null,分別調(diào)用String()顯式轉(zhuǎn)換為字符串。
- 可以看出,加法運(yùn)算中,如果有一個(gè)操作值為字符串類型,則將另一個(gè)操作值轉(zhuǎn)換為字符串,最后連接起來。
4. 乘除、減號(hào)運(yùn)算符、取模運(yùn)算符
這些操作符針對的是運(yùn)算,所以他們具有共同性:如果操作值之一不是數(shù)值,則被隱式調(diào)用Number()函數(shù)進(jìn)行轉(zhuǎn)換。
5.邏輯操作符(!、&&、||)
邏輯非(?。┎僮鞣紫韧ㄟ^Boolean()函數(shù)將它的操作值轉(zhuǎn)換為布爾值,然后求反。邏輯與(&&)操作符,如果一個(gè)操作值不是布爾值時(shí),遵循以下規(guī)則進(jìn)行轉(zhuǎn)換:
- 如果第一個(gè)操作數(shù)經(jīng)Boolean()轉(zhuǎn)換后為true,則返回第二個(gè)操作值,否則返回第一個(gè)值(不是Boolean()轉(zhuǎn)換后的值)
- 如果有一個(gè)操作值為null,返回null
- 如果有一個(gè)操作值為NaN,返回NaN
- 如果有一個(gè)操作值為undefined,返回undefined
邏輯或(||)操作符,如果一個(gè)操作值不是布爾值,遵循以下規(guī)則: - 如果第一個(gè)操作值經(jīng)Boolean()轉(zhuǎn)換后為false,則返回第二個(gè)操作值,否則返回第一個(gè)操作值(不是Boolean()轉(zhuǎn)換后的值)
- 對于undefined、null和NaN的處理規(guī)則與邏輯與(&&)相同
6.關(guān)系操作符(<, >, <=, >=)
與上述操作符一樣,關(guān)系操作符的操作值也可以是任意類型的,所以使用非數(shù)值類型參與比較時(shí)也需要系統(tǒng)進(jìn)行隱式類型轉(zhuǎn)換:
- 如果兩個(gè)操作值都是數(shù)值,則進(jìn)行數(shù)值比較
- 如果兩個(gè)操作值都是字符串,則比較字符串對應(yīng)的字符編碼值
- 如果只有一個(gè)操作值是數(shù)值,則將另一個(gè)操作值轉(zhuǎn)換為數(shù)值,進(jìn)行數(shù)值比較
- 如果一個(gè)操作數(shù)是對象,則調(diào)用valueOf()方法(如果對象沒有valueOf()方法則調(diào)用toString()方法),得到的結(jié)果按照前面的規(guī)則執(zhí)行比較
- 如果一個(gè)操作值是布爾值,則將其轉(zhuǎn)換為數(shù)值,再進(jìn)行比較
注:NaN是非常特殊的值,它不和任何類型的值相等,包括它自己,同時(shí)它與任何類型的值比較大小時(shí)都返回false。
7. 其他值到字符串的轉(zhuǎn)換規(guī)則?
- Null 和 Undefined 類型 ,null 轉(zhuǎn)換為 “null”,undefined 轉(zhuǎn)換為 “undefined”,
- Boolean 類型,true 轉(zhuǎn)換為 “true”,false 轉(zhuǎn)換為 “false”。
- Number 類型的值直接轉(zhuǎn)換,不過那些極小和極大的數(shù)字會(huì)使用指數(shù)形式。
- Symbol 類型的值直接轉(zhuǎn)換,但是只允許顯式強(qiáng)制類型轉(zhuǎn)換,使用隱式強(qiáng)制類型轉(zhuǎn)換會(huì)產(chǎn)生錯(cuò)誤。
- 對普通對象來說,除非自行定義 toString() 方法,否則會(huì)調(diào)用 toString()(Object.prototype.toString())來返回內(nèi)部屬性 [[Class]] 的值,如”[object Object]”。如果對象有自己的 toString() 方法,字符串化時(shí)就會(huì)調(diào)用該方法并使用其返回值。
8. 其他值到數(shù)字值的轉(zhuǎn)換規(guī)則?
- Undefined 類型的值轉(zhuǎn)換為 NaN。
- Null 類型的值轉(zhuǎn)換為 0。
- Boolean 類型的值,true 轉(zhuǎn)換為 1,false 轉(zhuǎn)換為 0。
- String 類型的值轉(zhuǎn)換如同使用 Number() 函數(shù)進(jìn)行轉(zhuǎn)換,如果包含非數(shù)字值則轉(zhuǎn)換為 NaN,空字符串為 0。
- Symbol 類型的值不能轉(zhuǎn)換為數(shù)字,會(huì)報(bào)錯(cuò)。
- 對象(包括數(shù)組)會(huì)首先被轉(zhuǎn)換為相應(yīng)的基本類型值,如果返回的是非數(shù)字的基本類型值,則再遵循以上規(guī)則將其強(qiáng)制轉(zhuǎn)換為數(shù)字。
為了將值轉(zhuǎn)換為相應(yīng)的基本類型值,抽象操作 ToPrimitive 會(huì)首先(通過內(nèi)部操作 DefaultValue)檢查該值是否有valueOf()方法。如果有并且返回基本類型值,就使用該值進(jìn)行強(qiáng)制類型轉(zhuǎn)換。如果沒有就使用 toString() 的返回值(如果存在)來進(jìn)行強(qiáng)制類型轉(zhuǎn)換。
如果 valueOf() 和 toString() 均不返回基本類型值,會(huì)產(chǎn)生 TypeError 錯(cuò)誤。
9. 其他值到布爾類型的值的轉(zhuǎn)換規(guī)則?
以下這些是假值: undefined、 null、 false、 +0、-0 和 NaN 、“”
假值的布爾強(qiáng)制類型轉(zhuǎn)換結(jié)果為 false。從邏輯上說,假值列表以外的都應(yīng)該是真值。
總結(jié)
- null、undefined 是相等的,且等于自身
- false 、 0、 '' 、 [] 是相等的
- NaN、{} 和什么都不相等,自己跟自己都不相等
NaN == NaN //false NaN == undefined //false NaN == false //false NaN == null //false NaN==[] //false NaN=='' //false NaN=={} //false false == false //true false == undefined //false false == null //false false == [] //true false == {} //false false == '' //true undefined == undefined //true undefined == null //true undefined == false //false undefined == [] //false undefined == {} //false undefined == '' //false null == null //true null == NaN //false null == [] //false null == {} //false null == undefined //true 0==false //true 0 == [] //true 0 == {} //false 0 == null //false 0 == undefined //false 0 == '' //true 0 == NaN //false false == [] //true false == {} //false false == null //false false == undefined //false false == '' //true false == NaN //false []=={} //false Boolean([]) //true Boolean({}) //true Boolean(null) //false Boolean(NaN) //false Boolean(undefined) //false Boolean('') //false Boolean(0) //false Number(undefined) //NaN Number({}) //NaN Number(NaN) //NaN Number('') //0 Number([]) //0 Number(false) //0 Number(null) //0
'2'>'10'為什么是true?
上面我們列了這么多轉(zhuǎn)換的規(guī)則,那么這道題我們就可以在上面這些規(guī)則中找到答案了,首先找到關(guān)系操作符,該規(guī)則中的第二點(diǎn)是兩個(gè)操作符都是字符串的話,則比較字符串對應(yīng)的字符編碼值,按我們常規(guī)思維是不是會(huì)覺得他會(huì)轉(zhuǎn)為數(shù)字再比較,然后2>10,返回false,然而并不是的,是不是覺得JavaScript很坑??。JavaScript
中用charCodeAt()
來獲取字符編碼
console.log('2'>'10') // true //首先將操作符兩邊都轉(zhuǎn)為字符編碼再進(jìn)行比較 '2'.charCodeAt() //50 '10'.charCodeAt() // 49 // 所以 '2'>'10' 會(huì)返回true
我們再來看幾道有趣(很坑)的題
1.復(fù)雜數(shù)據(jù)類型轉(zhuǎn)string
先調(diào)用valueOf()
獲取原始值,如果原始值不是string類型,則調(diào)用toString()
轉(zhuǎn)成string
console.log([1,2] == '1,2') //true [1,2].toString() // '1,2' var a = {} console.log(a.toString()) // "[object Object]" console.log(a == "[object Object]") //true
解析:
先將左邊數(shù)據(jù)類型轉(zhuǎn)成string,然后兩邊都是string,再比較字符編碼值
2.邏輯非隱式轉(zhuǎn)換與關(guān)系運(yùn)算符隱式轉(zhuǎn)換
console.log([] == 0) // true console.log(![] == 0) // true console.log([] == ![]) // true 是不是覺得很離譜??? console.log([] == []) //false console.log({} == !{}) //false console.log({} == {}) // false
看到這些結(jié)果是不是很吃驚,是的我也覺得很吃驚,簡直深坑。玩笑歸玩笑,我們還是一起來看看到底是為什么吧??!
解析:
console.log([] == 0) // true /*關(guān)系運(yùn)算符(3)如果只有一個(gè)操作值是數(shù)值,則將另一個(gè)操作值轉(zhuǎn)換為數(shù)值,進(jìn)行數(shù)值比較 原理: 1.[].valueOf().toString() 得到字符串"" 2.將""轉(zhuǎn)為數(shù)字Number("") 得到數(shù)字0 所以 [] == 0 成立 */ console.log(![] == 0) // true /* 原理:與上面類似,只是邏輯運(yùn)算符優(yōu)先級(jí)高于關(guān)系運(yùn)算符,所以先執(zhí)行![] 得到false false == 0 成立 */
console.log([] == ![]) // true /* 上面我們知道了 []==0 ![] == 0 所以 [] == ![] */ console.log([] == []) //false /* 引用數(shù)據(jù)類型數(shù)據(jù)存在堆中,棧中存儲(chǔ)的是它們的地址,兩個(gè)[]地址肯定不一樣,所以是false */
console.log({} == !{}) //false /* 原理: 1. {}.valueOf().toString() 得到"[object,Object]" 2. !{} == false 3. Number("[object,Object]") // NaN Number(false) //0 4. NaN != 0 */ console.log({} == {}) // false /* 引用數(shù)據(jù)類型數(shù)據(jù)存在堆中,棧中存儲(chǔ)的是它們的地址,所以肯定不一樣 */
JavaScript真值表
以上就是'2'>'10'==true?解析JS如何進(jìn)行隱式類型轉(zhuǎn)換的詳細(xì)內(nèi)容,更多關(guān)于JS隱式類型轉(zhuǎn)換的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
微信小程序 <swiper-item>標(biāo)簽傳入數(shù)據(jù)
這篇文章主要介紹了微信小程序 <swiper-item>標(biāo)簽傳入數(shù)據(jù)的相關(guān)資料,需要的朋友可以參考下2017-05-05一篇文章教你學(xué)會(huì)js實(shí)現(xiàn)彈幕效果
彈幕效果隨著b站的越做越強(qiáng),出現(xiàn)了越來越多的仿照b站的視頻站點(diǎn)。然而這些視頻站仿照的最多的只有一點(diǎn)!那就是彈幕,現(xiàn)在也越來越多的人喜歡上了彈幕本文就教你如何制作2021-08-08微信小程序 本地存儲(chǔ)及登錄頁面處理實(shí)例詳解
這篇文章主要介紹了微信小程序 本地存儲(chǔ)實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2017-01-01一文詳解webpack中l(wèi)oader與plugin的區(qū)別
這篇文章主要為大家介紹了一文詳解webpack中l(wèi)oader與plugin的區(qū)別詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02