前端JavaScript基础训练系列一百一十四:隐式强制类型转换为布尔值

现在我们来看看到布尔值的隐式强制类型转换,它最为常见也最容易搞错。
相对布尔值,数字和字符串操作中的隐式强制类型转换还算比较明显。下面的情况会发生 布尔值隐式强制类型转换。

(1)if (…)语句中的条件判断表达式。
(2)for ( … ; … ; … )语句中的条件判断表达式(第二个)。
(3) while (…) 和 do…while(…) 循环中的条件判断表达式。
(4)? :中的条件判断表达式。
(5) 逻辑运算符 ||(逻辑或)和 &&(逻辑与)左边的操作数(作为条件判断表达式)。
以上情况中,非布尔值会被隐式强制类型转换为布尔值,遵循前面介绍过的 ToBoolean 抽 象操作规则。
例如:

    var a = 42;
     var b = "abc";
     var c;
     var d = null;
     if (a) {
         console.log( "yep" );
}
// yep
while (c) {
    console.log( "nope, never runs" );
}
c = d ? a : b; c;
if ((a && d) || c) {
    console.log( "yep" );
}
// "abc"
// yep

上例中的非布尔值会被隐式强制类型转换为布尔值以便执行条件判断。

逻辑运算符 ||(或)和 &&(与)应该并不陌生,也许正因为如此有人觉得它们在
JavaScript 中的表现也和在其他语言中一样。
这里面有一些非常重要但却不太为人所知的细微差别。
我其实不太赞同将它们称为“逻辑运算符”,因为这不太准确。称它们为“选择器运算 符”(selector operators)或者“操作数选择器运算符”(operand selector operators)更恰 当些。
为什么?因为和其他语言不同,在 JavaScript 中它们返回的并不是布尔值。 它们的返回值是两个操作数中的一个(且仅一个)。即选择两个操作数中的一个,然后返

回它的值。

&& 和 || 运算符的返回值并不一定是布尔类型,而是两个操作数其中一个的值。 例如:

    var a = 42;
     var b = "abc";
     var c = null;
a || b; a && b;
c || b; c && b;
// 42
// "abc"
// "abc"
// null

在 C 和 PHP 中,上例的结果是 true 或 false,在 JavaScript(以及 Python 和 Ruby)中却 是某个操作数的值。
|| 和 && 首先会对第一个操作数(a 和 c)执行条件判断,如果其不是布尔值(如上例)就 先进行 ToBoolean 强制类型转换,然后再执行条件判断。
对于 || 来说,如果条件判断结果为 true 就返回第一个操作数(a 和 c)的值,如果为 false 就返回第二个操作数(b)的值。
&& 则相反,如果条件判断结果为 true 就返回第二个操作数(b)的值,如果为 false 就返 回第一个操作数(a 和 c)的值。
|| 和 && 返回它们其中一个操作数的值,而非条件判断的结果(其中可能涉及强制类型转 换)。c && b中c为null,是一个假值,因此&&表达式的结果是null(即c的值),而非 条件判断的结果 false。
现在明白我为什么把它们叫作“操作数选择器”了吧?
换一个角度来理解:

a || b;
// 大致相当于(roughly equivalent to): a ? a : b;
a && b;
// 大致相当于(roughly equivalent to): a ? b : a;

之所以说a || b与a ? a : b大致相当,是因为它们返回结果虽然相同但
是却有一个细微的差别。在a ? a : b中,如果a是一个复杂一些的表达式 (比如有副作用的函数调用等),它有可能被执行两次(如果第一次结果为 真)。而在a || b中a只执行一次,其结果用于条件判断和返回结果(如果
适用的话)。a && b和a ? b : a也是如此。 下面是一个十分常见的 || 的用法,也许你已经用过但并未完全理解:

     function foo(a,b) {
          a = a || "hello";
          b = b || "world";
          console.log( a + " " + b );
      }
      foo();                  // "hello world"
      foo( "yeah", "yeah!" ); // "yeah yeah!"

a = a || “hello”(又称为C#的“空值合并运算符”的JavaScript版本)检查变量a,如 果还未赋值(或者为假值),就赋予它一个默认值(“hello”)。
这里需要注意!

foo( "That’s it!", "" ); // "That’s it! world" 

第二个参数""是一个假值(falsyvalue,参见4.2.3节),因此b = b || "world"条件不成 立,返回默认值 “world”。
这种用法很常见,但是其中不能有假值,除非加上更明确的条件判断,或者转而使用? : 三元表达式。
通过这种方式来设置默认值很方便,甚至那些公开诟病 JavaScript 强制类型转换的人也经 常使用。
再来看看 &&。
有一种用法对开发人员不常见,然而 JavaScript 代码压缩工具常用。就是如果第一个操
作数为真值,则 && 运算符“选择”第二个操作数作为返回值,这也叫作“守护运算符” (guard operato),即前面的表达式为后面的表达式“把关”:

     function foo() {
          console.log( a );
      }
      var a = 42;
      a && foo(); // 42
   强制类型转换 | 75

foo()只有在条件判断a通过时才会被调用。如果条件判断未通过,a && foo()就会悄然 终止(也叫作“短路”,short circuiting),foo() 不会被调用。
这样的用法对开发人员不太常见,开发人员通常使用 if (a) { foo(); }。但 JavaScript 代码压缩工具用的是 a && foo(),因为更简洁。以后再碰到这样的代码你就知道是怎么 回事了。
|| 和 && 各自有它们的用武之地,前提是我们理解并且愿意在代码中运用隐式强制类型 转换。

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值