本翻译同时发布在平台众成翻译
附上原文链接
PS: 本文的一些点经常容易忘记,收藏一下随时来看看哦
你没有必要因为自己是一个JavaScript初学者而被以下这些迷惑…
1 | if ([0]) { |
或者这样…
1 | if ("potato") { |
好消息是,所有浏览器都得遵循一个标准。 有些作者会告诉你害怕胁迫和写码反对它。 我希望说服你,强制规则的特征我们可以利用(或至少理解),而不是去逃避…
x是true吗?x等于y?真假问题和等于运算,属于JavaScript的三个主要领域的核心问题:条件语句与运算符(if,三目运算,&&,||等),等于运算符(==)和严格相等运算符(===)。 让我们看看在每种情况下会发生什么…
条件语句Conditionals
在JavaScript中,所有条件语句和运算符都遵循相同的强制模式。 我们将以if
语句为例。
构造if
(表达式)_声明将强制使用抽象方法将表达式_转换为布尔值,在 ES5 spec中定义了以下算法规则:
参数类型 | 结果 |
---|---|
Undefined | false |
Null | false |
Boolean | 结果等于输入参数(无转换) |
Number | 如果参数为+0,-0或NaN,结果为false; 否则结果是true |
String | 如果参数是空字符串(其长度为零),则结果为false。 否则结果为true。 |
Object | true |
这是JavaScript用于将值分类为true(true
,“potato”
,36
,[1,2,4]
和{a:16}
)或false(false
,0
,""
,null
和undefined
)。
现在我们知道了为什么,在之前介绍的例子中,if([0])
允许进入后面的块:一个数组是一个对象,所有的对象被强制转换为true
。
以下还有几个例子。 一些结果可能令人惊讶,但他们始终坚持上述规定的简单规则:
1 | var trutheyTester = function(expr) { |
等于运算(==)
这个两个等号‘==’版本规则是相当宽松的。 即使左右两边是不同的类型,值也可以被认为是相等的,因为在执行比较之前,操作者将强制将一个或两个比较者转换为单一类型(通常为数字)。许多开发人员有点担心这种操作,无疑这至少有一个知名的JavaScript大师,会建议大家避免使用==操作符。
这种避免策略让我烦恼,因为除非你完全知道理解它,你才能掌握这种语言,而恐惧和逃避是知识的敌人。 另外假装忽略‘==’的存在并不会让你感到轻松了,因为在JavaScript强制转换是无处不在的!它在条件表达式(如我们刚刚看到的)中,它在数组索引中,它在连接操作处等等。 更强大的是,当我们能安全地使用它时,可以写出简洁,优雅和可读性高的代码。
无论如何,让我们看看ECMA定义的‘==’如何运作的方式。 它真的不是那么吓人。 只要记住undefined
和null
彼此相等(而没有别的),大多数其他类型被强制到一个数字以便于比较:
Type(x) | Type(y) | Result |
---|---|---|
x、y 相同类型 | x、y 相同类型 | 请参阅严格平等(===)算法 |
null | Undefined | true |
Undefined | null | true |
Number | String | x == toNumber(y) |
String | Number | toNumber(x) == y |
Boolean | (any) | toNumber(x) == y |
(any) | Boolean | x == toNumber(y) |
String or Number | Object | x == toPrimitive(y) |
Object | String or Number | toPrimitive(x) == y |
其他的类型组合 | 其他的类型组合 | false |
其中结果是表达式,则重新应用算法,直到结果为布尔值。 toNumber和toPrimitive是根据以下规则转换参数的js内部方法:
ToNumber
参数类型 | 结果 |
---|---|
Undefined | NaN |
Null | +0 |
Boolean | 如果参数是true结果为 1 . 如果参数是false结果为 +0 . |
Number | 结果等于输入(无转化) |
String | 有效计算Number(string) “abc” -> NaN “123” -> 123 |
Object | 遵循以下步骤: 1. 让 primValue进行 ToPrimitive(input argument, hint Number). 2. 返回 ToNumber(primValue). |
ToPrimitive
参数类型 | Result |
---|---|
Object | (在等于运算符强制转换的情况下)如果valueOf 返回一个原始值,则返回它。如果不是,则进行toString ,如果返回一个原始值,则返回。 否则会出错 |
其他 | 结果等于输入参数 (没有转换). |
这里有一些例子 —— 我将使用代码逐步演示如何应用各种强制转换规则
[0] == true;
1 | //‘等于’检查... |
“potato” == true;
1 | //校验是否等于... |
“potato” == false;
1 | //校验是否等于... |
object使用valueOf
1 | //校验是否等于... |
object使用toString
1 | //校验是否等于... |
严格相等运算符 (===)
这个很容易.如果运算符左右的类型不同,结果总是false。 如果它们是同一类型,则应用直观的等式测试:对象标识符必须引用相同的对象,字符串必须包含相同的字符集,其他原语必须共享相同的值。 NaN
,null
和undefined
永远不会===另一个类型。 NaN
甚至不===本身。
类型(x) | 值 | 结果 |
---|---|---|
类型(x) 与 类型(y)不同 | false | |
Undefined or Null | true | |
Number | x 和 y 值相同 (但是不是NaN ) |
true |
String | x 和 y 为相同字符 | true |
Boolean | x 和 y 都是true或者false | true |
Object | x 和 y 引用同一个对象 | true |
其他情况… | false |
一些使用等于判断不佳的例子
1 | //没必要 |
..因为 typeOf
是返回一个字符串的, 所以这个等于运算符总是在比较两个字符串. 因此 == 是 100% 的全等于。
1 | //没必要 |
…null 和 undefined 是始终等于(==)自己或对方的.
注意:由于undefined
变量可能被重新定义(非常小)的风险,所以等于null是稍微更安全的。
1 | //没必要 |
…不用我再解释,大家一定都懂啦 😉