前言

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



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

'2'>'10'==true? JS是如何进行隐式类型转换的?的更多相关文章

  1. js条件判断时隐式类型转换

    Javascript 中,数字 0 为假,非0 均为真 在条件判断运算 == 中的转换规则是这样的: 如果比较的两者中有布尔值(Boolean),会把 Boolean 先转换为对应的 Number,即 ...

  2. 【M21】利用重载技术避免隐式类型转换

    1.考虑UPint 的加法+,UPint a, b, result; 为了使result = a+10; result= 10+a; 都能通过编译,操作符重载如下: const UPint opera ...

  3. js中的一些隐式转换和总结

    js中的不同的数据类型之间的比较转换规则如下: 1. 对象和布尔值比较 对象和布尔值进行比较时,对象先转换为字符串,然后再转换为数字,布尔值直接转换为数字 [] == true; //false [] ...

  4. 深入js隐式类型转换

    前言 相信刚开始了解js的时候,都会遇到 2 =='2',但是 1+'2' == '1'+'2'为false的情况,这时候应该会是一脸懵逼的状态,不得不感慨js弱类型的灵活让人发指,隐式类型转换就是这 ...

  5. js隐式类型转换,预编译、递归、作用域,作用域链、闭包、立即执行函数、继承圣杯模式

    隐式类型转换 调用Number()当有运算符(加减乘除,求余)时,会调用Number()转为数字再运算,除了 加 当 有字符串时就变身成拼接Boolean();String(); typeof()st ...

  6. Javascript显示和隐式类型转换

    1.转换成字符串 多数的JavaScript宿主环境(比如Node.js和Chrome)都提供了全局函数toString: 与此同时Object.prototype也定义了toString方法,使得所 ...

  7. JavaScript显式类型转换与隐式类型转换

    隐式类型转换 四则运算 判断语句 toString 在 JavaScript 中声明变量不需指定类型,对变量赋值也没有类型检查,同时还允许隐式类型转换. 这些特征说明 JavaScript 属于弱类型 ...

  8. 「译」JavaScript 的怪癖 1:隐式类型转换

    原文:JavaScript quirk 1: implicit conversion of values 译文:「译」JavaScript 的怪癖 1:隐式类型转换 译者:justjavac 零:提要 ...

  9. JS--显示类型转换Number—隐式类型转换

    显示类型转换 (强制类型转换):Number()parseInt()parseFloat() Number是整体转换--能够把一个看起来像数字的字符串转成数字--尽量去转换能转的都转了 var a = ...

随机推荐

  1. 使用systemd将iptables规则在docker启动后自动导入

    编写systemd文件 $ sudo vi /etc/systemd/system/iptables-import.service # /etc/systemd/system/iptables-imp ...

  2. A Child's History of England.50

    'Knave [man without honor]!' said King Richard. 'What have I done to thee [you] that thou [you] shou ...

  3. How To Call An Ambulance

    How to Talk to the Emergency Dispatcher [minutesmatter.upmc稻糠亩] How To Call An Ambulance [askambulan ...

  4. 3.3 rust HashMap

    The type HashMap<K, V> stores a mapping of keys of type K to values of type V. It does this vi ...

  5. mysql与clickhouse的字段类型对应表

  6. Redis集群的三种模式

    一.主从模式 通过持久化功能,Redis保证了即使在服务器重启的情况下也不会损失(或少量损失)数据,因为持久化会把内存中数据保存到硬盘上,重启会从硬盘上加载数据. 但是由于数据是存储在一台服务器上的, ...

  7. Druid数据库监控

    一.简介 Druid是阿里开源的一个JDBC应用组件, 其包括三部分: DruidDriver: 代理Driver,能够提供基于Filter-Chain模式的插件体系. DruidDataSource ...

  8. 3.使用Spring Data ElasticSearch操作ElasticSearch(5.6.8版本)

    1.引入maven坐标 <!--spring-data-elasticsearch--><dependency> <groupId>org.springframew ...

  9. freeswitch APR库线程读写锁

    概述 freeswitch的核心源代码是基于apr库开发的,在不同的系统上有很好的移植性. 线程读写锁在多线程服务中有重要的作用.对于读数据比写数据频繁的服务,用读写锁代替互斥锁可以提高效率. 由于A ...

  10. Mysql配置文件 客户端

    [client] #默认链接的端口 port=3306 #默认链接的socket的位置 socket=/var/lib/mysql.sock #默认编码格式 default-character-set ...