关于前端:210true-JS是如何进行隐式类型转换的

6次阅读

共计 5292 个字符,预计需要花费 14 分钟才能阅读完成。

前言

‘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 真值表


我是 南玖,感激各位的:「点赞、关注和评论」,咱们下期见!

正文完
 0