摘要:正确的解释是允许在相等比较中进行强制类型转换,而不允许。参考资料小议下字符串比较大小中的强制类型转换核心概念类型转换对象和方法隐式类型转换小结
开胃菜
先说一个题外话,我在工作中遇到一个问题,需要比较 "08:00" 和 "09:00" 的大小,最后我找到三种方法:
在两个字符串前后各拼接相同的年月日和秒,拼成完整的时间格式进行比较:
var head = "2016-01-01 " var foot = ":00" var time1 = head + "08:00" + foot //"2016-01-01 08:00:00" var time2 = head + "09:00" + foot //"2016-01-01 09:00:00"
剩下的就不说了,比较两个完整的日期还是很容易的。
把两个字符串中的冒号去掉,转换成数字进行比较:
function timeToNumber(time) { let [head,foot] = time.split(":") return Number(head+foot) } var time1 = timeToNumber("08:00") //800 var time2 = timeToNumber("09:00") //900
直接比较
对,你没有看错,直接比较两个字符串:
"08:00" > "09:00" //false
看到这里估计有人就纳闷了,很明显第三种方法是更简洁的,但是字符串比较,好像很少见,它比较的依据是什么呢?
其实,字符串比较大小,会从左到右依次取两个字符串中的字符,两两比较他们charCodeAt()的结果,直到比较出大小就停止。比如:
var str1 = "a11" var str2 = "a2" // str1 和 str2 比较的时候,会先比较 str1[0] 和 str2[0],两个都是 "a",比较下一个 // str1[1] 是"1",charCodeAt()是49,str2[1] 是"2",结果是50,所以 str1[1] < str2[1],对比结束 // 最终结果 str1 < str2
同理,在比较"08:00" 和 "09:00"的时候,先比较两个"0",发现一致之后比较"8"和"9",所以"08:00" < "09:00"。
这里有一个问题就是,时间格式必须保持一致,位数不够的记得补"0",拿"8:00"和"10:00"比较会发现结果有问题,必须拿"08:00"和"10:00"比较才可以。
这个问题就说到这里,大家有其他的方法可以留言补充,给大家提供不同的思路。开胃菜结束,进入正题。
正题作为一个爱(记)学(不)习(清)的好(笨)孩子,通过字符串比较这件事,我意识到还有更多的非相同类型的比较,比如字符串和数字的比较,布尔和数组的比较(我疯了么我这么用),另外还有加减乘除等其他操作符。
我觉得有必要整理一下了。
我第一反应是这张图:
真是迷人的笑容呢 :)
在比较之前,我们需要先了解下各种数据类型转化的结果有哪些。
转数字
字符串:
空字符串是0
字符串头尾有空格会忽略
空格在中间,或者字符串中含有非数字类型字符,转换结果就是NaN
布尔:true -> 1, false -> 0
undefined字: NaN
null: 0
数组:
空数组是0
如果数组中有且只有一项是数字元素,转换为数字
其他情况NaN
对象:
如果对象有valueOf()方法,就调用该方法。如果返回基本类型值,就将这个值转化为数字
如果对象没有valueOf()方法或者该方法返回的不是基本类型值,就会调用该对象的toString()方法。如果存在且返回值是基本类型值,就转化为数字
否则就报错
函数:NaN
转字符串undefined -> "undefined"
null ->"null"
true -> "true" / false ->"false"
数字:极小和极大的数字使用指数形式,一般的情况你懂得
对象:
如果对象有toString()方法,就调用toString()方法。如果该方法返回基本类型值,就将这个值转化为字符串
如果对象没有toString()方法或者该方法返回的不是基本类型值,就会调用该对象的valueOf()方法。如果存在且返回值是基本类型值,就转化为字符串
否则就报错
除非自行定义,否则toString()返回内部属性[[Class]]的值,如"[object Object]"
转布尔所有的假值(undefined、null、+0、-0、NaN、"")会被转化为 false,其他都会被转为true
所以,空对象、空数组都是true
转对象null和undefined转对象直接抛异常
基本类型通过调用String()、Number()、Boolean()构造函数,转换为他们各自的包装对象
使用场景知道了各种数据类型转化的规则,那么在不同的场景中,究竟是怎么使用的呢?
== 运算符常见的误区是:==检查值是否相等,===检查值和类型是否相等。
正确的解释是:==允许在相等比较中进行强制类型转换,而===不允许。
事实上,==和===都会检查操作数的类型,区别在于类型不同时它们的处理方式不同。
如果一个值是null,另一个值是undefined,则相等
如果一个是字符串,另一个值是数字,则把字符串转换成数字,进行比较
如果任意值是true,则把true转换成1再进行比较;如果任意值是false,则把false转换成0再进行比较
如果一个是对象,另一个是数值或字符串,把对象转换成基础类型的值再比较
对象转基础类型时,优先调用valueOf(),再调用toString()。
例外的是Date,Date 利用的是toString()转换
经典题[] == false // true !![] // true //原因是 == 两边都转为数字进行比较,而不是 [] 转为布尔值与 false 比较+ 运算符
+ 运算符可以作为一元运算符使用,此时的作用是将后边跟着的数据转为数字
+true // 1 +[] // 0 +new Date() //获取当前时间的Unix时间戳
在作为二元运算符使用时,+运算符比- * /运算符要复杂一些,因为其他的运算符都是处理数字的,而+运算符还可以处理字符串拼接。
两边如果有字符串,另一边会转化为字符串进行相加
如果没有字符串,两边都会转化为数字进行相加,对象也根据前面的方法转化为数字
如果其中的一个操作数是对象,则将对象转换成原始值,日期对象会通过 toString()方法进行转换,其他对象通过valueOf()方法进行转换,但是大多数都是不具备可用的valueOf()方法,所以还是会通过toString()方法执行转换
简单来说就是,如果+运算符的其中一个操作数是字符串(或者通过以上步骤可以得到字符串),那么就执行字符串拼接,否则执行数字加法。
经典题!+[]+[]+![] //"truefalse" //首先第一个 + 左边不是数值,所以它是一元运算符,将后边跟着的 [] 转化为数字 0 //同时,最后一个 [] 左边是 ! 运算符,将 [] 转化为布尔值并取反,为 false //转化后的结果为 !0 + [] + false //!0 结果为 true,[] 转化为 "",所以结果变为 true + "" + false //因为 第一个 + 右边有字符串,所以变为"true" + false //最终结果为 "truefalse"条件判断
以下条件判断的语句,会发生隐式转换为布尔值的情况:
if()语句中的条件判断表达式
for(..; ..; ..)语句中的条件判断表达式
while()和do .. while()
? : 中的条件判断表达式
||和&&左边的操作数
补充:valueOf()和toString()常用内置对象调用toString()和valueOf()的返回情况
类型 | toString | valueOf |
---|---|---|
Object | "[object 类型名]" | 对象本身 |
String | 字符串值 | 字符串值 |
Number | 返回数值的字符串表示。还可返回以指定进制表示的字符串,默认10进制 | 数字值 |
Boolean | "true" / "false" | Boolean 值 |
Array | 每个元素转换为字符串,用英文逗号作为分隔符进行拼接 | 数组本身 |
Date | 日期的文本表示,格式为Wed Jun 05 2019 18:22:32 GMT+0800 (中国标准时间) | 返回时间戳,等同于调用getTime() |
Function | 函数的文本表示 | 函数本身 |
RegExp | 正则的文本表示 | 正则本身 |
以上是本篇文章的内容,欢迎大家提出自己的想法,我们一起学习进步,与君共勉。
参考资料小议js下字符串比较大小
JavaScript中的强制类型转换
JavaScript核心概念(1):类型转换
js对象tostring和valueof方法
JavaScript隐式类型转换小结
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/104472.html
摘要:在各大浏览器厂商的发展过程中,它们对的标准各有不同的实现,标准不同存在差异所以产生兼容性的问题。它是一种对特定的浏览器或浏览器组显示或隐藏规则或声明的方法。但是及更低版本浏览器会继续解析。 为什么会存在浏览器兼容问题? 首先要了解兼容,我们先得了解一下为什么会存在浏览器兼容问题。在各大浏览器厂商的发展过程中,它们对web的标准各有不同的实现,标准不同存在差异所以产生兼容性的问题。 浏览...
摘要:配置涵盖了目前的业务场景的基本需求,但是可扩展性很低。最终决定采用的生态链来解决上述遇到的问题。在指定的路径下写入对应的文件。 大纲 遇到的问题场景及解决方案对比 什么是babel? 解决过程 目前遗留的问题 目前实现功能API 参考 遇到的问题场景及解决方案对比 我们目前采用的是antd + react(umi)的框架做业务开发。在业务开发过程中会有较多频繁出现并且相似度很高的场...
阅读 1391·2021-10-11 10:58
阅读 1473·2021-09-04 16:41
阅读 672·2019-08-30 15:55
阅读 800·2019-08-29 18:46
阅读 3134·2019-08-29 14:05
阅读 3525·2019-08-26 14:00
阅读 2448·2019-08-26 13:53
阅读 3166·2019-08-26 13:29