一、逻辑运算符常用于布尔(逻辑)值之间;当操作数都是布尔值时,返回值也是布尔值。
二、&& 和 || 返回的是一个特定的操作数的值,所以当它用于非布尔值的时候,返回值就可能是非布尔值。
三、逻辑运算符
| 运算符 | 范例 | 描述 | 示例 |
|---|---|---|---|
| 逻辑与(&&) | expr1 && expr2 | (逻辑与)如果expr1能被转换为false,那么返回expr1;否则,返回expr2。 | var a1 = true && true // true var a2 = true && false // false var a3 = false && true // false var a8 = false && false // false var a4 = false && (3 == 4) // false var a5 = ‘Cat’ && ‘Dog’ // Dog var a6 = flase && ‘Cat’ // false var a7 = ‘Cat’ && false // false |
| 逻辑或(||) | expr1 || expr2 | (逻辑或)如果expr1能被转换为true,那么返回expr1;否则,返回expr2 | var o1 = true || true // true var o2 = false || true // true var o3 = true || false // true var o4 = false || (3 == 4) // false var o5 = ‘Cat’ || ‘Dog’ // Cat var o6 = false || ‘Cat’ // Cat var o7 = ‘Cat’ || false // Cat |
| 逻辑非(!) | !expr | (逻辑非)如果操作数能够转换为true则返回false;否则返回true | var n1 = !true // false var n2 = !false // true var n3 = !’Cat’ // false |
1、&&用于布尔值时,当操作数都为true时返回true
2、|| 用于布尔值时,当任何一个操作数为true则返回true,是false则返回false
四、能被转换为false/ falsy的值有null, 0 , NaN, 空字符串(””)和undefined
五、与运算&&的优先级比或运算||要高
【示例1】a && b || c && d 跟 && 表达式加了括号完全一样:(a && b) || (c && d)
六、不要用 || 或 && 来取代if
一、有时候,有人会将与运算符&&作为“简化if”的一种方式。
【示例1】
let x = 1;(x > 0) && alert( 'Greater than zero!' );
1、&&右边的代码只有运算抵达到那里才能被执行。也就是,当且仅当(x > 0)为真。
2、所以我们基本可以类似地得到:
let x = 1;if (x > 0) alert( 'Greater than zero!' );
3、虽然使用&&写出的变体看起来更短,但if更明显,并且往往更具可读性。因此,我们建议根据每个语法结构的用途来使用:如果我们想要if,就使用if;如果我们想要逻辑与,就使用&&。
短路求值 (Short-circuit evaluation)
一、作为逻辑表达式进行求值是从左到右,它们是为可能的“短路”的出现而使用以下规则进行测试:
【示例1】
false && anything // 被短路求值为falsetrue || anything // 被短路求值为true
1、逻辑的规则,保证这些评估是总是正确的。
2、上述表达式中的anything部分不会被求值,所以这样做不会产生任何副作用。
运算符类型
|| (或)
一、一个或运算 || 的链,将返回第一个真值,如果不存在真值,就返回该链的最后一个值
或运算寻找第一个真值
一、例如,我们有变量firstName、lastName和nickName,都是可选的(即可以是 undefined,也可以是假值)。
1、我们用或运算||来选择有数据的那一个,并显示出来(如果没有设置,则用”Anonymous”):
let firstName = "";
let lastName = "";
let nickName = "SuperCoder";
alert( firstName || lastName || nickName || "Anonymous"); // SuperCoder
如果所有变量的值都为假,结果就是"Anonymous"。
2、如果所有变量的值都为假,结果就是”Anonymous”。
短路求值(Short-circuit evaluation)
一、|| 对其参数进行处理,直到达到第一个真值,然后立即返回该值,而无需处理其他参数
二、如果操作数不仅仅是一个值,而是一个有副作用的表达式,例如变量赋值或函数调用,那么这一特性的重要性就变得显而易见了。
【示例1】
true || alert("not printed"); // 或运算符 || 在遇到 true 时立即停止运算,所以 alert 没有运行。
false || alert("printed");
&& (与)
与运算寻找第一个假值
一、与运算返回第一个假值,如果没有假值就返回最后一个值
【示例1】
// 如果第一个操作数是真值,
// 与运算返回第二个操作数:
alert( 1 && 0 ); // 0
alert( 1 && 5 ); // 5
// 如果第一个操作数是假值,
// 与运算将直接返回它。第二个操作数会被忽略
alert( null && 5 ); // null
alert( 0 && "no matter what" ); // 0
【示例2】可以在一行代码上串联多个值。查看第一个假值是如何被返回的
alert( 1 && 2 && null && 3 ); // null
【示例3】如果所有的值都是真值,最后一个值将会被返回
alert( 1 && 2 && 3 ); // 3,最后一个值
| 【示例】jsx中的bug
1、错误写法```javascript
<br />错误原因:taskInfo.notAllowedCount值为0,是假值。与运算符直接返回它。<br />2、正确写法```javascript
<div>
本次不可导入{title}数量
{taskInfo.notAllowedCount !== 0 && (
<span className={styles.exportText}>导出明细</span>
)}
</div>
|
| —- |
! (非)
一、感叹符号!表示布尔非运算符
二、语法
result = !value;
三、逻辑非运算符接受一个参数,并按如下运作:
1、将操作数转化为布尔类型:true/false。
2、返回相反的值。
【示例1】
alert( !true ); // false
alert( !0 ); // true
四、两个非运算!!有时候用来将某个值转化为布尔类型:
alert( !!"non-empty string" ); // true
alert( !!null ); // false
1、也就是,第一个非运算将该值转化为布尔类型并取反,第二个非运算再次取反。最后我们就得到了一个任意值到布尔值的转化。
2、一个内置的Boolean函数,可以完成同样的事 :
【示例1】
alert( Boolean("non-empty string") ); // true
alert( Boolean(null) ); // false
五、非运算符 ! 的优先级在所有逻辑运算符里面最高,所以它总是在 && 和 || 之前执行。
?? 空值合并运算符
一、我们将值既不是null也不是undefined的表达式称为“已定义的(defined)”。
二、空值合并运算符(nullish coalescing operator)的写法为两个问号??。
三、a ?? b的结果是:
- 如果a是已定义的,则结果为a,
- 如果a不是已定义的,则结果为b。
1、换句话说,如果第一个参数不是null/undefined,则??返回第一个参数。否则,返回第二个参数。
四、空值合并运算符并不是什么全新的东西。它只是一种获得两者中的第一个“已定义的”值的不错的语法。
【示例1】我们可以使用我们已知的运算符重写result = a ?? b,像这样:
result = (a !== null && a !== undefined) ? a : b;
四、空值合并运算符??提供了一种从列表中选择第一个“已定义的”值的简便方式。
五、通常??的使用场景是,为可能是未定义的变量提供一个默认值。
【示例1】如果user是未定义的,我们则显示Anonymous:
let user;
alert(user ?? "Anonymous"); // Anonymous
当然,如果user的值为除null/undefined外的任意值,那么我们看到的将是它:
let user = "John";
alert(user ?? "Anonymous"); // John
六、我们还可以使用??序列从一系列的值中选择出第一个非null/undefined的值。
【示例1】假设我们在变量firstName、lastName或nickName中存储着一个用户的数据。如果用户决定不输入值,则所有这些变量的值都可能是未定义的。
1、我们想使用这些变量之一显示用户名,如果这些变量的值都是未定义的,则显示 “Anonymous”。
2、让我们使用??运算符来实现这一需求:
let firstName = null;
let lastName = null;
let nickName = "Supercoder";
// 显示第一个已定义的值:
alert(firstName ?? lastName ?? nickName ?? "Anonymous"); // Supercoder
与 || 比较
一、或运算符||可以以与??运算符相同的方式使用。
【示例1】在上面的代码中,我们可以用||替换掉??,也可以获得相同的结果:
let firstName = null;
let lastName = null;
let nickName = "Supercoder";
// 显示第一个真值:
alert(firstName || lastName || nickName || "Anonymous"); // Supercoder
1、或||运算符自 JavaScript 诞生就存在,因此开发者长期将其用于这种目的。
二、另一方面,空值合并运算符??是最近才被添加到 JavaScript 中的,它的出现是因为人们对 || 不太满意。
三、它们之间重要的区别是:
- || 返回第一个真值。
- ?? 返回第一个已定义的值。
1、换句话说,|| 无法区分false、0、空字符串””和null/undefined。它们都一样 —— 假值(falsy values)。如果其中任何一个是||的第一个参数,那么我们将得到第二个参数作为结果。
四、在实际中,我们可能只想在变量的值为null/undefined时使用默认值。也就是说,当该值确实未知或未被设置时。
【示例1】考虑下面这种情况:
let height = 0;
alert(height || 100); // 100
alert(height ?? 100); // 0
- height || 100首先会检查height是否为一个假值,发现它确实是。
- 所以,结果为第二个参数,100。
- height ?? 100首先会检查height是否为null/undefined,发现它不是。
- 所以,结果为height的原始值,0。
1、如果高度0为有效值,则不应将其替换为默认值,所以 ?? 能够得出正确的结果。
优先级
一、??运算符的优先级相当低:在MDN table中为5。因此,??在=和?之前计算,但在大多数其他运算符(例如,+和*)之后计算。
二、如果我们需要在还有其他运算符的表达式中使用??进行取值,需要考虑加括号:
【示例1】
let height = null;
let width = null;
// 重要:使用括号
let area = (height ?? 100) * (width ?? 50);
alert(area); // 5000
1、否则,如果我们省略了括号,则由于*的优先级比??高,它会先执行,进而导致错误的结果。
// 没有括号
let area = height ?? 100 * width ?? 50;
// ……与下面这行代码的计算方式相同(应该不是我们所期望的):
let area = height ?? (100 * width) ?? 50;
?? 与 && 或 || 一起使用
一、出于安全原因,JavaScript 禁止将??运算符与&&和||运算符一起使用,除非使用括号明确指定了优先级。
【示例1】下面的代码会触发一个语法错误:
let x = 1 && 2 ?? 3; // Syntax error
1、这个限制无疑是值得商榷的,但它被添加到语言规范中是为了避免人们从||切换到??时的编程错误。
2、可以明确地使用括号来解决这个问题:
let x = (1 && 2) ?? 3; // 正常工作了
alert(x); // 2
