前言

'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. 数仓:解读 NameNode 的 edits 和 fsimage 文件内容

    一.edits 文件 一)文件组成 一个edits文件记录了一次写文件的过程,该过程被分解成多个部分进行记录:(每条记录在hdfs中有一个编号) 每一个部分为: '<RECORD>...& ...

  2. 学习java 7.7

    学习内容: 多态转型:向上转型 Animal a = new Cat(); a.eat(); 向下转型 Cat c = (Cat)a; c.eat(); 抽象方法没有方法体,抽象类中有抽象方法 抽象类 ...

  3. 学习java 7.2

    学习内容:案例一:斐波那契数列从1开始作为第一个数,求第20个数 public class Test { public static void main(String[ ] args){ int[ ] ...

  4. github小白的记录随笔

    此文章是基础本地安装好了git环境的新手小白. 进入您要上传项目的根路径,右键选择Git Bash Here. 输入命令: git init //初始化git仓库环境 git remote add o ...

  5. day9 图书设计项目

    总路由层url from django.conf.urls import url from django.contrib import admin from app01 import views ur ...

  6. Fllin(七)【Flink CDC实践】

    目录 FlinkCDC 1.简介 2.依赖 3.flink stream api 4.flink sql 5.自定义反序列化器 6.打包测试 FlinkCDC 1.简介 CDC是Change Data ...

  7. ORACLE 本session产生的redo

    select * from v$statname a ,v$mystat bwhere a.STATISTIC# = b.STATISTIC# and a.name = 'redo size';

  8. java.util.Collections.copy()方法注意点

    今天发现单独的将一个ArrayList的对象添加到另外一个ArrayList的时候,总是源列表和目的列表相同的内存地址.原因如下: 偶然看到了Collections的copy(List desc,Li ...

  9. idea如何在git上将分支代码合并到主干

    1.首先将idea中的代码分支切换到master分支,可以看到我们在dev上提交的代码 在master上是没有的 2.如图所示,在remote branch 上选择分支,点击后面的三角图标,展开之后选 ...

  10. ssm+mysql+jsp打造在线考试系统WeKnow-学生端

    一.登陆模块 前台提交账号和密码传到后台处理控制层 1.1 首先是控制器 @RequestMapping(value="/studentLogin", method=Request ...