'2'>'10'==true? JS是如何進行隱式類型轉換的?


前言

'2'>'10'返回的true,可能很多人都不是很能理解吧? 在js中,當運算符在運算時,如果兩邊數據不統一,CPU就無法計算,這時我們編譯器會自動將運算符兩邊的數據做一個數據類型轉換,轉成一樣的數據類型再計算。 這種無需程序員手動轉換,而由編譯器自動轉換的方式就稱為隱式轉換。

如果這篇文章有幫助到你,❤️關注+點贊❤️鼓勵一下作者,文章公眾號首發~

想要知道'2'>'10'為什么是true,我們得先來了解一下JavaScript的隱式類型轉換規則。

隱式類型轉換規則

1. == 操作符的強制類型轉換規則?

  • 字符串和數字之間的相等比較,將字符串轉換為數字之后再進行比較。
  • 其他類型和布爾類型之間的相等比較,先將布爾值轉換為數字后,再應用其他規則進行比較。
  • null 和 undefined 之間的相等比較,結果為真。其他值和它們進行比較都返回假值。
  • 對象和非對象之間的相等比較,對象先調用 ToPrimitive 抽象操作后,再進行比較。
  • 如果一個操作值為 NaN ,則相等比較返回 false( NaN 本身也不等於 NaN )。
  • 如果兩個操作值都是對象,則比較它們是不是指向同一個對象。如果兩個操作數都指向同一個對象,則相等操作符返回true,否則,返回 false。

2.遞增遞減操作符(前置與后置)、一元正負操作符

這些操作符適用於任何數據類型的值,針對不同類型的值,該操作符遵循以下規則(經過對比發現,其規則與Number()規則基本相同):

  • 如果是包含有效數字字符的字符串,先將其轉換為數字值(轉換規則同Number()),在執行加減1的操作,字符串變量變為數值變量。
  • 如果是不包含有效數字字符的字符串,將變量的值設置為NaN,字符串變量變成數值變量。
  • 如果是布爾值false,先將其轉換為0再執行加減1的操作,布爾值變量編程數值變量。
  • 如果是布爾值true,先將其轉換為1再執行加減1的操作,布爾值變量變成數值變量。
  • 如果是浮點數值,執行加減1的操作。
  • 如果是對象,先調用對象的valueOf()方法,然后對該返回值應用前面的規則。如果結果是NaN,則調用toString()方法后再應用前面的規則。對象變量變成數值變量。

3.加法運算操作符

加號運算操作符在Javascript也用於字符串連接符,所以加號操作符的規則分兩種情況:
如果兩個操作值都是數值,其規則為:

  • 如果一個操作數為NaN,則結果為NaN
  • 如果是Infinity+Infinity,結果是Infinity
  • 如果是-Infinity+(-Infinity),結果是-Infinity
  • 如果是Infinity+(-Infinity),結果是NaN
  • 如果是+0+(+0),結果為+0
  • 如果是(-0)+(-0),結果為-0
  • 如果是(+0)+(-0),結果為+0

如果有一個操作值為字符串,則:

  • 如果兩個操作值都是字符串,則將它們拼接起來
  • 如果只有一個操作值為字符串,則將另外操作值轉換為字符串,然后拼接起來
  • 如果一個操作數是對象、數值或者布爾值,則調用toString()方法取得字符串值,然后再應用前面的字符串規則。對於undefined和null,分別調用String()顯式轉換為字符串。
  • 可以看出,加法運算中,如果有一個操作值為字符串類型,則將另一個操作值轉換為字符串,最后連接起來。

4. 乘除、減號運算符、取模運算符

這些操作符針對的是運算,所以他們具有共同性:如果操作值之一不是數值,則被隱式調用Number()函數進行轉換。

5.邏輯操作符(!、&&、||)

邏輯非(!)操作符首先通過Boolean()函數將它的操作值轉換為布爾值,然后求反。
邏輯與(&&)操作符,如果一個操作值不是布爾值時,遵循以下規則進行轉換:

  • 如果第一個操作數經Boolean()轉換后為true,則返回第二個操作值,否則返回第一個值(不是Boolean()轉換后的值)
  • 如果有一個操作值為null,返回null
  • 如果有一個操作值為NaN,返回NaN
  • 如果有一個操作值為undefined,返回undefined
    邏輯或(||)操作符,如果一個操作值不是布爾值,遵循以下規則:
  • 如果第一個操作值經Boolean()轉換后為false,則返回第二個操作值,否則返回第一個操作值(不是Boolean()轉換后的值)
  • 對於undefined、null和NaN的處理規則與邏輯與(&&)相同

6.關系操作符(<, >, <=, >=)

與上述操作符一樣,關系操作符的操作值也可以是任意類型的,所以使用非數值類型參與比較時也需要系統進行隱式類型轉換:

  • 如果兩個操作值都是數值,則進行數值比較
  • 如果兩個操作值都是字符串,則比較字符串對應的字符編碼值
  • 如果只有一個操作值是數值,則將另一個操作值轉換為數值,進行數值比較
  • 如果一個操作數是對象,則調用valueOf()方法(如果對象沒有valueOf()方法則調用toString()方法),得到的結果按照前面的規則執行比較
  • 如果一個操作值是布爾值,則將其轉換為數值,再進行比較
    注:NaN是非常特殊的值,它不和任何類型的值相等,包括它自己,同時它與任何類型的值比較大小時都返回false。

7. 其他值到字符串的轉換規則?

  • Null 和 Undefined 類型 ,null 轉換為 “null”,undefined 轉換為 “undefined”,
  • Boolean 類型,true 轉換為 “true”,false 轉換為 “false”。
  • Number 類型的值直接轉換,不過那些極小和極大的數字會使用指數形式。
  • Symbol 類型的值直接轉換,但是只允許顯式強制類型轉換,使用隱式強制類型轉換會產生錯誤。
  • 對普通對象來說,除非自行定義 toString() 方法,否則會調用 toString()(Object.prototype.toString())來返回內部屬性 [[Class]] 的值,如”[object Object]”。如果對象有自己的 toString() 方法,字符串化時就會調用該方法並使用其返回值。

8. 其他值到數字值的轉換規則?

  • Undefined 類型的值轉換為 NaN。
  • Null 類型的值轉換為 0。
  • Boolean 類型的值,true 轉換為 1,false 轉換為 0。
  • String 類型的值轉換如同使用 Number() 函數進行轉換,如果包含非數字值則轉換為 NaN,空字符串為 0。
  • Symbol 類型的值不能轉換為數字,會報錯。
  • 對象(包括數組)會首先被轉換為相應的基本類型值,如果返回的是非數字的基本類型值,則再遵循以上規則將其強制轉換為數字。

為了將值轉換為相應的基本類型值,抽象操作 ToPrimitive 會首先(通過內部操作 DefaultValue)檢查該值是否有valueOf()方法。如果有並且返回基本類型值,就使用該值進行強制類型轉換。如果沒有就使用 toString() 的返回值(如果存在)來進行強制類型轉換。

如果 valueOf() 和 toString() 均不返回基本類型值,會產生 TypeError 錯誤。

9. 其他值到布爾類型的值的轉換規則?

以下這些是假值: undefined、 null、 false、 +0、-0 和 NaN 、“”

假值的布爾強制類型轉換結果為 false。從邏輯上說,假值列表以外的都應該是真值。

總結

  • 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?

上面我們列了這么多轉換的規則,那么這道題我們就可以在上面這些規則中找到答案了,首先找到關系操作符,該規則中的第二點是兩個操作符都是字符串的話,則比較字符串對應的字符編碼值,按我們常規思維是不是會覺得他會轉為數字再比較,然后2>10,返回false,然而並不是的,是不是覺得JavaScript很坑🦢。JavaScript中用charCodeAt()來獲取字符編碼

console.log('2'>'10') // true

//首先將操作符兩邊都轉為字符編碼再進行比較

'2'.charCodeAt() //50
'10'.charCodeAt() // 49

// 所以 '2'>'10' 會返回true

我們再來看幾道有趣(很坑)的題

1.復雜數據類型轉string

先調用valueOf()獲取原始值,如果原始值不是string類型,則調用toString()轉成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

解析:

先將左邊數據類型轉成string,然后兩邊都是string,再比較字符編碼值

2.邏輯非隱式轉換與關系運算符隱式轉換

console.log([] == 0) // true
console.log(![] == 0) // true 

console.log([] == ![])  // true  是不是覺得很離譜???
console.log([] == [])  //false

console.log({} == !{}) //false
console.log({} == {})  // false

看到這些結果是不是很吃驚,是的我也覺得很吃驚,簡直深坑。玩笑歸玩笑,我們還是一起來看看到底是為什么吧!!

解析:

console.log([] == 0) // true
/*關系運算符(3)如果只有一個操作值是數值,則將另一個操作值轉換為數值,進行數值比較
原理:
1.[].valueOf().toString() 得到字符串""
2.將""轉為數字Number("") 得到數字0
所以 [] == 0 成立

*/
console.log(![] == 0) // true 
/*
原理:與上面類似,只是邏輯運算符優先級高於關系運算符,所以先執行![] 得到false
false == 0 成立
*/
console.log([] == ![])  // true  
/*
上面我們知道了 []==0 ![] == 0 
所以 [] == ![]
*/
console.log([] == [])  //false
/*
引用數據類型數據存在堆中,棧中存儲的是它們的地址,兩個[]地址肯定不一樣,所以是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
/*
引用數據類型數據存在堆中,棧中存儲的是它們的地址,所以肯定不一樣
*/

JavaScript真值表

真值表.png
我是南玖,感謝各位的:「點贊、關注和評論」,我們下期見!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM