2-21 隐式类型转换
不夸张地说,类型转换在ECMAScript中无时无刻不在进行。有些类型转换浅显易见,例如使用内置函数来进行类型转换,代码如下:
这种使用函数手动进行类型转换的方式常常被称为显式类型转换,显式转换一般不会为代码带来风险。作为开发者,我们可以一眼看出转换前后的类型。在ECMAScript中,最令开发者提心吊胆的是隐式转换,稍不留神就会掉入其中的陷阱。
当你将数字与字符串进行相加操作时,数字会被隐式转换成字符串再进行加操作,这在前边的案例中也有介绍。其实在ECMAScript中,对象之间的加操作也会被隐式转换成字符串,例如:
加法运算符虽然会经常产生隐式转换,但是其并不是真正的雷区。真正的雷区是关系运算符。前面介绍过,在进行相等比较时,ECMAScript中提供了两种运算符,一种是相等运算符“==”,另一种是全等运算符“===”。前面我们说全等运算符要求除了值相等外,类型也要相等。其实这是一种不正确的说法(只是因为便于理解记忆并且比较流行,所以我们姑且这么说),相等与全等运算符的真正区别在于相等运算符会进行隐式类型转换,而全等运算符不会。第一种说法会让你误认为全等运算符做了更多工作:既比较值又比较类型。实际上恰好相反,相等运算符做的工作更多:比较前先进行隐式类型转换。我们来看一个简单的命题:
有变量a, a == !a一定不成立。
这个命题乍看上去必然为真,那么我们通过代码来测试一下:
上面的打印结果为true,你一定目瞪口呆,一个值的取反竟然和它本身是相等的。如果你了解隐式类型转换的过程,这个神奇的结果其实一点也不神奇。首先,对字符串"0"进行逻辑非运算时,会被转换成逻辑值false,进行等于比较运算时,逻辑值false会被隐式类型转换为数值0,而字符串"0"也会被隐式转换成数值0,因此比较的结果为true。相等运算符在进行不同类型间的比较时,大部分情况都会朝数值的方向进行隐式类型转换,在使用时一定要格外注意。
还有一些经常会令开发者疑惑的情况,请看下面的命题:
(1)有变量a和b,且都不等于NaN,则a>b、a<b和a==b中一定有一个是成立的。
(2)有变量a和b,且都不等于NaN,则a>=b和a<=b中一定有一个是不成立的。
这两个命题看上去都是无懈可击的,看过如下代码,你就会改变想法了:
奇怪吧,上面的代码前3个全部打印了false,当对“对象”进行大于或小于比较时,会将其隐式转换为字符串,对象转换成字符串后都为[object Object],因此前两个log语句都打印了false。而针对a==b的比较,这里并没有进行隐式类型转换,回忆一下前面讲解过的值类型与引用类型就能豁然开朗,对于对象只有其引用完全相同时,才算相等。
第2个命题也是假的,后两个打印了true,击破这个命题的原因在于ECMAScript中对“>=”和“<=”两种运算符的运算会自动被转换成“<”和“>”。
隐式类型转换是ECMAScript中的一把双刃剑,其给开发者编写代码带来便利的同时,也存在很多隐患,在编写代码时一定要多多注意。