大家好,又见面了,我是你们的朋友全栈君。
(注:此篇博客主要讨论相等运算符的类型转换)
发现问题
几天前在审查公司实习生代码时查出一个bug,代码是这样写的:
pic1
他这里的业务是先从接口中拿到某个对象的数据,如果这个对象为空的话会将它赋值为null,
如果对象有值做进一步处理,如果对象的str属性不为空再做某些处理。
当然,这里做if判断的话完全没有必要写这个==true 直接通过obj和str来判断就可以了 即
pic2
但是最开始的时候我也不觉得他的写法(pic1)有什么逻辑上的影响,后来才发现这两种写法有着天差地别。pic1中的两个if判断都会永远返回false。
案例解析
首先我们现在控制台打几个简单的语句
我们可以得出:
(结论1)将所有对象包括空对象转成布尔值都会返回true(不包括null)。
(结论2)我们都知道if语句条件判断的括号中可以放变量,也可以放表达式。
- 如果括号中是变量的话,则直接将其转换为布尔值。
- 如果括号中是表达式,则先将表达式运算出结果后再将结果取布尔值。
所以针对两个案例中的第一个if判断我们可以模拟出
很明显,第一个判断返回值为true,第二个if判断返回值是false,
我们来分析一下上边这段代码,
首先第一个判断相当于Boolean(o),根据结论1,这个返回值一定是true。
第二个判断会先计算o==true的结果,然后再将其转换为布尔值,可能有少部分同学也会想当然的以为这里会先将o转换为布尔值,和等号右边的类型相同后再作比较,
我们可以在控制台打一下这个表达式:
如果是先将o转成布尔值后再与true做比较的话,返回值一定为true即:
可见他不是这样转换的,那么它是怎样转换的呢?
我去查了一下红宝书,是这样规定的:
在执行相等运算符时,如果有一方类型为布尔值,那么会将布尔值转换为数字类型后再比较
那在我们这个例子中布尔值true被转换成1,那等号另一端的对象是怎样转换的呢?于是我往下翻,还有这样一条:
如果有一方为对象,另一方为非对象,则执行对象的valueOf方法后得到基本数据类型再作比较,如果得不到基本数据类型,再执行它得toString方法后进行比较。
那我们先看一下我们实例化的对象o继承Object原型上默认定义的valueOf方法和toString()方法会返回什么
所以我们可以猜想o==true判断时经历了以下几个步骤:
- 执行o的valueOf方法,返回对象本身
- valueOf的返回值不是基本数据类型,执行它的toString方法,返回字符串”[Object Object]”
- 将true转换为数据类型,返回1
- 判断 “[Object Object]” 是否全等于 1
- 返回false
为了验证我们上边的猜想,我在控制台写了以下代码:
足以证明我们的猜想步骤是正确的。
然而我们案例中的第二个判断字符串与布尔值比较也是将其先转换成数值后再进行比较。
相当于:Number(o.str) === Number(true)
前者返回NaN,后者返回1,当然不等。
类型扩展
我们上面的案例是解决了,但是其他类型的相等运算符是怎样转换的呢?
我先提出两个问题
1.大家都知道 null==undefined 返回的结果为true,那么它是怎样进行类型转换的呢?
2.null==0 undefined==0的返回值分别是多少?
不卖关子,直接说答案
第一个问题
不会进行类型转换
误区:有的同学可能以为null和undefined都会先转换为布尔值,然后再判断相等性。
正确思路:其实他们的相等是js规定的,这里不会进行类型转换。
第二个问题
返回值都为false
误区:如果按照案例中的思路有些人可能会以为null和undefined也是都会被转换为Number后再做判断。
对undefined来讲Number(undefined)返回值为NaN,与0相比返回false很正常,
但是Number(null)的返回值为0 为什么也与0相比返回false呢?
正确思路:其实这里js规定Null和undefined与其他数据类型比较时不会进行类型转换,所以返回结果都为false。
更多类型的相等运算符比较:
转载于:https://juejin.im/post/5ca6040d518825440563e64e
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/106888.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...