本篇文章选自作者angus-c的博客,博客地址
由我这个英语垃圾进行翻译………………
JavaScript中的真或假
就算你不是一个JS新手,也会被下面的语句感到迷惑吧:
又或者像这样:
|
|
好消息是所有的浏览器有一个统一的标准。一些作者将会告诉你如何使用代码去解决这个让人害怕的矛盾。我希望你要相信这个矛盾会让你在学习中更上一个台阶(或者彻底的理解它),你要做的是尝试理解而不是逃避。
x是’true’吗?x和y相等吗?有关于是否为真,是否相等的问题是JS三个主要领域中的核心问题。条件的声明和操作(比如if语句,三元判断法,与或非等等),等式的操作(==),和严格等式的操作(===)。让我们看看这些都会发生些那些有趣的事情呢?
条件语句
在JS中,所有的条件声明和操作都遵循着相同的强制规范,我们使用if
声明举一个例子:
当我们声明了一个if
表达式的时候,他会将返回的结果强制的变为布尔值。这是使用了一种抽象的ToBoolean
模块,一个在ES5中所定义的一种算法
数据类型 | 返回结果 |
---|---|
Undefined | false |
Null | false |
Boolean | 结果等同于你输入的值 |
Number | +0,-0,和NaN的结果为false,其他数字为true |
String | 如果字符串为空(长度为0)返回的结果为false,其他情况为true |
Object | true |
JS有一些经典的真值和假值:
真值(true
,'potato'
,36
,[1,2,3]
,{a:16}
),假值(false
,0
,' '
,null
,undefined
)
现在我们就可以弄清关于开场时我们举得几个例子,if([0])
能够运行的原因是:一个数组就是一个对象,所有的对象返回的结果都为true
。为什么会这样呢?就是因为if
表达式将[0]
解析成为一个对象,所以结果就成为了true
,这样就会运行if
表达式后面的代码。
这里有一些小例子,有些结果或许会出乎你的意料,但是他们始终坚持上述规定的简单规则:
等式算法(==)
==
的判断并不会那么严格,两个不同类型的值也有可能相等。在进行两个不同类型的值进行判断相等运作时,这种算法会将==
式的一边或两边暴力的转化为单一的数据类型(通常是数字)。毫无疑问,最后一个众所众知的JS权威专家建议尽量避免使用==运算符。
这种回避策略使我不安的一点是因为你没有完全的明白这个语言的全部的时候,你是无法掌握这个语言的,而且一味的回避和害怕是知识的敌人。除此以外,当==
运算符出现并且你无奈的想要理解它的时候,假装==运算符不存在也不会让你摆脱这种疑惑,因为这种暴力算法存在于JS的每一个角落。他存在于条件表达式中(向我们刚刚看到的那种),在数组的索引中,存在于越来越多的地方。所以使用安全模式这种强制性的要求很有必要,这会让你的更加简洁,优雅并且具有可读性。
无论如何,无奈的怒吼一下之后,我们还是要了解一下在EMEC的定义中==
是怎么工作的。这并不是那么的恐怖。只要记住undefined
和null
两者是相等的,并且大多数其他的数据类型为了便利的进行比较将会暴力的转化为一个数字。
数据类型x | 数据类型y | 比较结果 |
---|---|---|
x和y是相同的类型 | 参考严格模式下的算法(===) | |
Null | Undefined | true |
Number | String | x == toNumber(y) |
String | Number | toNumber(x) == y |
Boolean | (any) | toNumber(x) == y |
(any) | Boolean | x == toPrimitive(y) |
Object | String or Number | toPrimitive(x) == y |
其他情况 | false |
下面我们参考一下上面的描述进行几个小例子:
当结果是一个表示式的时候,算法将会再一次的运行,直到结果成为一个布尔值。toNumber
和toPrimitive
是当进行强制性的转化数据类型时隐藏在==
运算符内部的模块,他们的转化规则如下:
ToNumber
数据类型 | 返回结果 |
---|---|
Undefined | NaN |
NaN | +0 |
Boolean | 如果是true时,值为1,如果是false时,值为+0 |
Number | 结果等于输入的值 |
String | 取决于字符串的内容是否为数字,’abc’->NaN ‘123’->123 |
Object | 运行步骤:1使用ToPrimitive 将对象转化为原始类型的值 2再将原始值使用ToNumber 转化为数字 |
ToPrimitive
数据类型 | 返回结果 |
---|---|
Object | (在强制的等式运算符情况下)如果valueOf 返回值是一个原始值,返回它,其他情况如果toString 返回值是一个原始值得,返回它。再或者的情况下会返回一个error |
其他情况 | 值就是输入的值 |
这里有一些例子,我将用伪代码来解释这些强制算法是怎么一步一步的运算的:
[0] == true;
|
|
‘potato’ == true
|
|
‘potato’ == false
|
|
object with valueOf
|
|
object with toString
|
|
严格相等模式(===)
这是很简单的一个模式了。如果运算符两边的数据类型不同,答案永远都是’false’。如果他们是相同的数据类型,我们直观的都可以判断到:两个值的引用必须来自同一个对象,数组,或者函数。字符串必须包含相同的字符格式,各个位上的字符都相等。其他原始值也必须是相等的值和长度。NaN
,null
和undefined
永远不等于其他数据类型,NaN
甚至不等于它自己。
数据类型x | 值 | 比较结果 |
---|---|---|
x和y是不相同的类型 | false | |
Null or Undefined | true | |
Number | x和y相等但不是NaN |
true |
String | x和y字符格式相等,长度相等 | true |
Boolean | x和y同时为true或false | true |
Object | x和y引用自同一个对象 | true |
其他情况 | false |
常见的不宜使用严格相等的例子
|
|
因为typeOf
返回的是字符串,等式两边永远是两个字符串在进行比较。所以这个==就等同于===。
|
|
null 和 undefined 在 == 中是相等的。
注意:因为将变量定义为undefined
会有一点点小风险,所以变量等于null
是比较安全的做法。
|
|
这个就不用说太多。科科…
引用文章:
ECMA-262 第五版
11.9.3 The Abstract Equality Comparison Algorithm
11.9.6 The Strict Equality Comparison Algorithm
9.1 toPrimitive
9.2 toBoolean
9.3 toNumber