原文链接:https://javascript.info/logical-operators,translate with ❤️ by zhangbao.
在 JavaScript 中,包含 3 个逻辑运算符:||()、&&(与)、!(非)。
虽然他们称为“逻辑”,但是可以应用在任何类型上,不单是布尔值,结果也可以是任意类型的。
我们详细看下.
||(或)
“或”运算符用两个垂直的线符号表示:
result = a || b;
在经典编程中,逻辑或仅仅是为了操纵布尔值。如果其中有一个运算数是 true,那么结果为 true,否则结果就是 false。
在 JavaScript 中,操作符有点棘手和强大,但是首先让我们看看布尔值会发生什么。
有四种可能的逻辑组合:
alert( true || true ); // true
alert( false || true ); // true
alert( true || false ); // true
alert( false || false ); // false
我们可以看到,除非两个操作数同时为 false,否则结果都返回 true。
如果一个操作数不是布尔值,那么它就会被转换成布尔值来进行计算。
例如,数值 1 会作为 true 对待,数值 0 则是作为 false 对待:
if (1 || 0) { // works just like if( true || false )
alert( 'truthy!' );
}
多数时间,或 || 会在 if 语句里使用测试给定条件里有满足的判断:
例如:
let hour = 9;
if (hour < 10 || hour > 18) {
alert( '办公室关门了.' );
}
我们可以使用更多的条件判断:
let hour = 12;
let isWeekend = true;
if (hour < 10 || hour > 18 || isWeekend) {
alert( 'The office is closed.' ); // it is the weekend
}
或会查找第一个真值
上面描述的逻辑有些经典。现在让我们引入 JavaScript 的“额外”特性。
扩展算法的工作原理如下。
给定多个或操作数:
result = value1 || value2 || value3;
或 || 操作符会做下列操作:
从左到右计算操作数。
对于每个操作数,将其转换为布尔值。如果结果为 true,则终止并且返回操作数的原始值。
如果处最后一个的所有操作数都已经被计算了(即都是 false),那么返回最后一个操作数。
值是以原始形式返回的,没有转换。
也就是说,或 || 会返回逻辑链上的第一个真值,如果都是假值,则返回最后一个值作为运算结果。
例如:
alert( 1 || 0 ); // 1 (1 是真值)
alert( true || 'no matter what' ); // (true 是真值)
alert( null || 1 ); // 1 (1 是第一个真值)
alert( null || 0 || 1 ); // 1 (第一个真值)
alert( undefined || null || 0 ); // 0 (都是假值,返回最后一个值)
这就引出了一些有趣的用法,与“纯粹的,经典的,只做布尔值的或”相比。
- 从一列变量或者表达式里获得第一个真值
假设我们有几个变量,可能包含数据或者 null/undefined。我们需要选择第一个有数据的。
我们可以使用或 ||:
let currentUser = null;
let defaultUser = "John";
let name = currentUser || defaultUser || "unnamed";
alert( name ); // 结果是 "John" – 第一个真值
如果 currentUser 和 defaultUser 都是假值的话,那么结果就会是 “unnamed”。
- 短路计算
操作数不仅可以是值,还可以是任意表达式。或操作数从左到右对它们进行计算和判断。当遇到第一个真值时,计算终止,并且返回值。这个过程被称为“短路计算”,因为它从左到右尽可能短。
当第二个参数给出的表达式可以有副作用,这显然是可见的。比如一个变量赋值。
如果我们执行下面代码的话,x 不会被赋值:
let x;
true || (x = 1);
alert(x); // undefined, because (x = 1) not evaluated
赋值是一个简单的例子,可以涉及到其他副作用。
正如我们所看到的,这样的用例是一种“更短的 if 方法”。第一个操作数被转换成布尔值,如果它是假的,那么第二个操作数就会被计算。
大多数情况下,最好使用“常规”if 来保持代码的易于理解,但有时使用或又很方便。
&&(与)
与操作符用 && 表示:
result = a && b;
在传统编程里,与在两个操作数都是真值时返回 true,否则返回 false:
alert( true && true ); // true
alert( false && true ); // false
alert( true && false ); // false
alert( false && false ); // false
一个 if 语句的例子:
let hour = 12;
let minute = 30;
if (hour == 12 && minute == 30) {
alert( 'Time is 12:30' );
}
类似或,与运算符的操作数可以是任意类型的:
if (1 && 0) { // evaluated as true && false
alert( "won't work, because the result is falsy" );
}
与会查找第一个假值
给定多个与操作数:
result = value1 && value2 && value3;
与 && 操作符会做下列操作:
从左到右计算操作数。
对于每个操作数,将其转换为布尔值。如果结果为 false,则终止并且返回操作数的原始值。
如果处最后一个的所有操作数都已经被计算了(即都是 true),那么返回最后一个操作数。
也就是说,或 || 会返回逻辑链上的第一个假值,如果都是真值,则返回最后一个值作为运算结果。
这个规则类似于或,不同点是与返回第一个假值,而或返回第一个真值。
例子:
// 如果第一个操作数为真,
// 与返回第二个操作数:
alert( 1 && 0 ); // 0
alert( 1 && 5 ); // 5
// 如果第一个操作数是假值,
// 与就返回它,第二个操作数会被忽略
alert( null && 5 ); // null
alert( 0 && "no matter what" ); // 0
我们还可以连续传递几个值。看看第一个返回的假值:
alert( 1 && 2 && null && 3 ); // null
当所有值都是真值的时候,就返回最后一个值:
alert( 1 && 2 && 3 ); // 3, the last one
⚠️与 && 的优先级比或 || 要高
与 && 的优先级比或 || 要高
因此代码 a && b || c && d 本质上等同于 && 两边的操作数包围在括号里:(a && b) || (c && d)。
类似于或,与 && 操作符有时可以替换 if。
例如:
let x = 1;
(x > 0) && alert( 'Greater than zero!' );
&& 右边部分的操作只有在前面条件满足时,才会执行。也就是仅当 (x > 0) 为 true 时。
所以我们基本上有一个类似的东西:
let x = 1;
if (x > 0) {
alert( 'Greater than zero!' );
}
可以看到,明显 && 形式的写法更加简短。但是 if 更加直观,并且更加可读。
所以使用每个结构来实现它的目的。如果我们要用如果,就使用 if,如果想用与就使用 &&。
!(非)
布尔非运算符用一个惊叹号 ! 来表示。
语法超级简单:
result = !value;
操作员接受一个单一的参数,并执行以下操作:
将操作数转换成布尔类型:true/false。
返回相反的值。
例如:
alert( !true ); // false
alert( !0 ); // true
两个非运算符 !! 有时用于将值转换为布尔类型:
alert( !!"non-empty string" ); // true
alert( !!null ); // false
也就是说,第一个不会将值转换成布尔值并返回相反的值,第二个不会反过来。最后,我们有一个简单的值对布尔转换方法。
还有一种更详细的方法来做同样的事情——内置的 Boolean 函数:
alert( Boolean("non-empty string") ); // true
alert( Boolean(null) ); // false
非运算符的优先级是所有位操作里最高的,所以它总是最先执行,也就是在 &&,|| 之前。
(完)