本文是关于JavaScript的陷阱和最佳实践中的一部分。
===
而不是==
===
&& ==
在JavaScript
中,有二种判断值是否相等的等性运算符:
===
ES5 11.9.6描述了===
的具体算法。我们以x === y
为例:
x
和y
的类型不同,返回false
Undefined
或Null
,返回true
Number
x
或y
为NaN
,返回false
x
和y
的数值相等,返回true
x
为+0
且y
为-0
,返回true
,反之亦然false
String
,那么很明显,必须两者包含相同的字符串才会返回true
,否则返回false
Number
,与String
类型情况一样,必须两者同时为true
或false
才会返回true
,否则返回false
x
和y
两者都指向同一个对象时,返回true
,否则返回false
注意:
NaN
并不等于它自己,即NaN === NaN
返回false
。所以我们必须使用其它方法来判断某个值是否为NaN
。
==
ES5 11.9.3描述了==
的具体算法。我们以x == y
为例:
x
和y
的类型相同,则使用===
算法比对x
为null
且y
为undefined
,则返回true
,反之亦然Number
类型,另外一个是String
类型,那么需要先把String
类型的转换为Number
,然后再执行==
Boolean
类型,另外一个是非Boolean
类型,那么需要先把Boolean
类型转换为Number
类型,然后再执行==
String
或是Number
类型,另外一个是Object
类型,那么需要先把Object
类型转换为primitive的类型,然后再执行==
false
在比较时,该运算符还遵守下列规则:
null
和undefined
相等null
和undefined
转换成其他值NaN
,等号将返回false
,非等号将返回true
true
,否则两个运算数不相等即使两个数都是
NaN
,等号仍然返回false
,因为根据规则,NaN
不等于NaN
。
==
带来的问题从上面的分析,我们可以看到如果使用==
,可能会带来一些问题:
==
做判等时,如果两者类型不同,则需要做大量的类型转换,而这些类型转换规则并不是一眼就能看出来的,如果你稍不留意,结果就可能与你想像的大不相同==
可以允许任意的类型做判断,所以一些类型错误就有可能难以发现比如:
true == 2
为false
是因为true
首先会被转化为1,然后再执行1 == 2
,所以返回false
。
大家可能会觉得最后一个例子'\r\n\t 111 \t' == 111
很奇怪,为什么它会返回true
?那是因为'\r\n\t 111 \t'
在执行==
前,必须先转换为Number
,而这样会删除掉数值前后的空白符。
==
我们经常给JavaScript初学者的其中一个建议就是尽量使用===
而不是==
,毫无疑问,这是完全正确的,特别是对一个初学者来说。但是有些情况下,我们可能会觉得使用==
更合乎常理,但是他们其实不是看上去那样美的。
虽然你的代码只写了一次,但是它会被你和其他人读多次,所以代码的可读性是非常重要的。
undefined
和null
比较如果你看完了上面的分析,那么你就会知道,使用==
时,undefined
和null
之间是互等的,但是与其它值判等时都是false
。所以,我们经常会用下在的代码来判断一个值是否为undefined
或null
:
乍一看,这样判断代码简短,但是可读性很弱,无法完全表达作者原有的意思。如果一个JavaScript初学者看到这段代码,他可能会以为你只是在检测null
,但是如果是一个经验丰富的前端工程师的话,他可能会认为你写错,其实你是想用===
。如下所示:
如果你还想更精简一点,那么可以这样写:
在JavaScript中,
false
,null
,0
,''
,undefined
和NaN
都被当做false
值。
在处理与后端交互的Ajax请求返回结果时,我们经常需要去处理返回的以字符串形式展现的数值,如id: '111111'
。这个时候,我们可能经常会这样去做比较:
这个时候,我们是去检查id
是111111
或是'111111'
。
但是,如果别人来看你的代码时,他会认为id
是Number
类型的。那么,为什么不直接告诉读你代码的人它是我们需要的是Number
类型的呢?如果不是,我们需要先进行显示的类型转换。
由于==
支持类型不同的值的比较的,所以你也用它来比较对象和原生数据类型值。
如果你看到下面的这段代码,你会认为写这段代码的人是想做什么?
str
可能是一个String
类型的包装对象,你是想让一个对象和字符串进行比较吗?如果是,你得了解这个对象是如何转换为原生数据类型的。str
先转换为字符串吗?如果是,你可以让你的代码更清楚点str
是一个String
类型的包装对象,你想得到对象的原始值,然后再做比较?比如,当我们以函数的形式调用String
构造函数时,它会自动完成类型转换,如下代码所示:
你知道String(foo)
返回的肯定会是String
类型,所以这里使用==
是没有任何问题的,因为我们可以保证这里不可能会有任何的类型转换的。
但是,我们仍然可以不用这样做:
==
,并没有给我们带来任何收益,那么我们为什么不使用更简单的===
呢?===
是判断是否相等最简单的方法,那是因为它并不会对它的操作数进行类型转换。虽然性能测试结果在所有的JavaScript引擎中不尽相同,但对大多数浏览器来说,===
与==
性能差不多,甚至更快。虽然许多种情况下,看似使用==
不伤大雅,但是不使用==
已经是一条不成文的规则,不仅仅是对新手而已。
代码中少一些花哨,那么就更容易理解和维护。