隐式强制类型转换
- •
+
运算符既能用于加法运算,也能用于字符串拼接。
var a = "42"; var b = "0"; var c = 42; var d = 0; a + b; // "420" c + d; // 42
- • S:
如果 + 运算符中其中一个操作数是字符串,则执行字符串拼接,否则执行加法运算。
隐式强制类型转换为布尔值
- • (1) if (..) 语句中的条件判断表达式。
- • (2) for ( .. ; .. ; .. ) 语句中的条件判断表达式(第二个)。
- • (3) while (..) 和 do..while(..) 循环中的条件判断表达式。
- • (4) ? : 中的条件判断表达式。
- • (5) 逻辑运算符 ||(逻辑或)和 &&(逻辑与)左边的操作数(作为条件判断表达式)。
- •
|| 和 &&
- • 他们的
返回值两个操作数中的其中一个
。
var a = 42; var b = "abc"; var c = null; a || b; // 42 a && b; // "abc" c || b; // "abc" c && b; // null
- •
|| 和 && 操作符会对第一个操作数进行条件判断,且会对第一个操作数进行隐式类型转换(会通过 toBoolean 操作),然后再进行条件判断。
- •
|| 运算符,如果条件判断结果为true, 就返回第一个操作数的结果。如果为 false, 就返回第二个操作数的结果。
- •
&& 运算符则相反,如果条件判断结果为 true 就返回第二个操作数结果,如果为 false, 就返回第一个操作数的结果。
a || b; // 大致相当于 a ? a : b; a && b; // 大致相当于 a ? b : a;
宽松相等(==)和严格相等(===)
- • 宽松相等 == 与严格相等 === 都是用于判断两个值是否相等。但他们之间有一个重要的区别,特别是在
判断条件上
。 - • 在之前的了解和很多文章中很多人这样聊到:
== 检查值是否相等, === 检查值和类型是否相等
。这么说听起来蛮有道理,但不够准确。正确的解释应该是:== 允许在相等比较中进行强制类型转换,而 === 不允许
两种操作符的性能
- • 根据第一种(
== 检查值是否相等, === 检查值和类型是否相等
)解释:严格相等(===) 比 宽松相等(==) 似乎做的事情更多,因为它还要检查值的类型。而第二种(== 允许在相等比较中进行强制类型转换,而 === 不允许
) 解释: 宽松相等(==) 似乎做的事情更多,如果值类型不同还需要进行强制类型转换。 - • 这样下来,有人觉得 == 比 === 慢,实际上确实 == 在强制类型转换的时候需要花费时间,但这个时间为微妙级的(百万分之一秒)。所以,
在进行比较两个值类型相同的情况下,使用 == 与 === 没有什么区别
。如果两个值类型不同,这时候就要考虑有没有强制类型转换的必要,有就用 ==,没有就用 ===,不需要在乎性能
。 - • == 和 === 他们都会检查操作数的类型,区别在于操作数类型不同时他们的处理方式的不同。
字符串和数字之间的相等比较
var a = 42; var a = "42"; a === b; // false a == b; // true
- • a === b 因为没有强制类型转换,所以 a === b 为 false, 也就是 42 和 "42" 不相等。
- • a == b 因为是宽松相等,即当两个值类型不同时,则对其中一个值进行强制类型转换。那如何转换,是转换 a,还是转换 b 呢?
- • ES5 规范 11.9.3.4-5 规则:
- •
如果 Type(x) 为数字,Type(y) 为字符串,则返回 x == toNumber(y) 的结果
- •
如果 Type(x) 为字符串,Type(y) 是数字,则返回 toNumber(x) == y 的结果
- • 所以根据以上规则,"42" 会被进行 toNumber 转换然后进行相等比较,所以 42 == 42 为 true。
其他类型与布尔类型之间的相等比较
- • == 很容易出错的一个地方就是 true、false 和其他类型之间的相等比较。
var a = "42"; var b = true; a == b; // false
- • 我们知道变量 a 为字符串 "42" 是一个真值,那为什么 a == b 会返回 false 呢?
- • ES5 规范 11.9.3.6-7 规则:
- •
如果 Type(x) 是布尔类型,则返回 toNumber(x) == y 的结果
- •
如果 Type(y) 是布尔类型,则返回 x == toNumber(y) 的结果
- • 所以根据以上规则, Type(b) 为布尔类型,所以会对 b 进行 toNumber 操作,然后就是 true = 1, 根据字符串与数字之间的比较规则可得出 42 != 1,所以结果为 false。
- • 所以现在你搞懂了吗???
- • "42" 是一个真值没错,但 "42" == true 并没有发生布尔值比较和强制类型转换。这里并不是 "42" 转换为布尔值,而是 true 进行 toNumber 操作。
- • 所以我们要搞清 == 对不同类型的组合会怎样处理,
== 两边的布尔值会进行 toNumber 操作
。 - • 所以建议大家不管什么情况下都不要使用 == true 和 == false 来判断。但对于 === 来说,它不会发生强制类型转换,所以不需要进行 toNumber 操作。
var a = "42"; // 不要这样用,条件判断不成立: if (a == true) { // .. } // 也不要这样用,条件判断不成立: if (a === true) { // .. } // 这样的显式用法没问题: if (a) { // .. } // 这样的显式用法更好: if (!!a) { // .. } // 这样的显式用法也很好: if (Boolean( a )) { // .. }
null 和 undefined 之间的相等比较
- • ES5 规范 11.9.3.2-3 规则:
- •
如果 x 为 null, y 为 undefined, 则结果为 true
- •
如果 x 为 undefined, y 为 null, 则结果为 true
- • 在 == 中 null 和 undefined 相等且他们也与自身相等,除此之外不存在这种情况。也就是说
在 == 中的 null 和 undefined 是一回事,可进行隐式的强制类型转换
。
var a = null; var b; a == b; // true a == null; // true b == null; // true null == undefined; // true null == null; // true undefined == undefined; // true a == false; // false b == false; // false a == ""; // false b == ""; // false a == 0; // false b == 0; // false
- • 所以我们
可将 null 和 undefined 作为等价来处理
。
var a = doSomething(); if (a == null) { // .. }
- • 以上的 if 判断语句只有当 a 为 null 或 undefined 时才成立,除此之外都不成立,包含 0, false 和 ''。
对象与非对象之间的相等比较
- • 关于对象(对象、函数、数组)与基本类型(字符串、数字,布尔值)之间的相等比较。
- • ES5规范 11.9.3.8-9 规则如下:
- •
如果 Type(x) 是字符串或数字,Type(y) 是对象,则返回 x == toPromitive(y) 的结果
- •
如果 Type(x) 是对象,Type(y) 是字符串或数字,则返回 toPromitive(x) == y 的结果
var a = 42; var b = [ 42 ]; a == b; // true
- • [ 42 ] 首先调用 toPromitive 抽象操作,返回 "42",变成 "42" == 42,然后又变成 42 == 42,最后二者相等。