[JavaScript 随笔] 理解相等判断(==、===)和类型转换 - 名一
JavaScript 中大概有这几种 “类型”:
undefined
null
string
boolean
number
object
function
之所以在 “类型” 上加了双引号,是因为严格来说,null 的类型是 object。但本文讨论的主题包括了关于 null 的类型转换,它和 object 不同,所以单独列出来了。这点请根据上下文强行区分一下,不是bug、不是bug、不是bug。
有趣的例子
'0' == 0; // true0 == ''; // true'0' == ''; // false
这里展示的是相等比较的非传递性。即,如果有 a == b, b == c,并不代表 a == c。
如果说
'1' == true;'0' == false;
这两个是常识,那对于一些特殊的字符串,你能正确判断吗?
'001' == true;'002' == false; // 注意!'0x0' == false;'\n' == false;
非严格相等(==)
当使用 == 比较,并且两侧的类型不同时,会触发隐式类型转换。标准中定义的转换规则很长,其核心就是,1、类型不同时,尽量转成 数字 比较;2、特例。(类型相同就按该类型的值判断,不特殊说明了,难道 '123' 还能等于 '456' 不成?)
关于特例,其实也就是 null 和 undefined 。也就是说,以下几个表达式是永远为 true 的。
undefined == null;null == undefined;NaN != NaN; // 注意!null != 非null; // 注意!null 与非 null 值永远是不等的
所以也不需要再去深追为什么 undefined 和 null 是相等的,因为按照“规则”已经无法解释了,这是一种“约定”。OK,剩下的情况是转数字。
null 的数值是 0
undefined 的数值是 NaN
true 是 1,false 是 0
至于字符串,嗯,有点复杂
object:调用 toString 或 valueOf 后转成基本类型,再转数字
第一条,在这里没用,因为涉及到 null 的比较时,除非 null == null,其他情况都是不等的。即
null != 0;
第二条,在这里没用,因为涉及到 NaN 的比较时,都是不等。
第三条,有点用,很有用!
1 == true; // 对2 == true; // 错!
第四条,麻烦。80% 情况下,对于 '123' 转成 123,'abc' 转成 NaN,'' 转成 0,这三条记住就可以了。
'123' == 123;'' == 0;'abc'; // 转成数值是 NaN
另外的情况,由于字符串的组合形式各种各样,很难三言两语总结完,大致有:
空白字符串转成 0,'\n' == 0
十六进制、八进制正常转换,'0xff' == 255
数字字符串会忽略首尾空白字符,正常转,'\n123\n' == 123
数字字符和其他字符混合时,转成 NaN,如 '123abc'
现在回头去看“有趣的例子”,是不是一目了然。(嗯,不谢)
条件判断
暂且把 if - else 和 condition ? a : b; 中的判断情况称为条件判断吧。(场景还有取反、for、while 等)
等于 true 的值一定是 truthy,但等于 false 的值不一定是 falsy 。
例
new Boolean(false) == false; // 这个没问题吧?new Boolean(false) ? 'a' : 'b'; // 表达式的值是 'a'!
只能说,条件判断中对真假的判定和相等判断是不一样的。 显然,相等判断是基于数字比较的,而条件判断是基于布尔值。
关于布尔值的转换规则:
null, undefined, NaN 都是 false
字符串,仅当空字符串('')时为 false,其他都是 true
object,都是 true (仅 null 除外)
我见过其他一些相等判断的技巧:
!!x == true;+x == 123;
取反操作会把变量强转成 boolean;一元 + 会把变量强转成 number。
也见过一些用的不太合适的地方(?):
if (!!x) // ...
在条件判断中本身会做强转的操作,为了可读性?不见得有提高。
严格相等(===)
严格相等的逻辑相对简单粗暴,如果类型不同,就不考虑隐式转换了,直接为假。如果类型相同:
布尔、数字、字符串就看字面值是否相等
object,看引用是否相同
主要是考虑什么时候用 ==,什么时候用 === 。
很简单,只有在要求类型相同时,才用 ===,否则用 ==
有些场景的确只有非严格相等才能做,比如
var b = new Boolean(false);b === false // 竟然是错的b == false // 对b ? 'a' : 'b' // 竟然是 'a'
结论就是当涉及到对象比较时,稍微斟酌一下。而对于像 typeof x 它一定会返回 string,这时用 == 比较就更合适一些。
小结
涉及到 == 比较,并且需要隐式转换时,会转成 number。
涉及到条件判断,自然是转成 boolean。
涉及到二元 +、- 等数值计算时,从左至右优先转成 number,除非是遇到 string,则做字符串拼接操作。