2022 年 6 月 5 日

逻辑运算符

JavaScript 中有四个逻辑运算符:||(OR)、&&(AND)、!(NOT)、??(空值合并)。这里我们介绍前三个,?? 运算符在下一篇文章中介绍。

虽然它们被称为“逻辑”,但它们可以应用于任何类型的变量,而不仅仅是布尔值。它们的结果也可以是任何类型。

让我们看看详情。

|| (OR)

“OR”运算符用两个竖线符号表示

result = a || b;

在经典编程中,逻辑 OR 旨在仅处理布尔值。如果其任何参数为 true,则返回 true,否则返回 false

在 JavaScript 中,该运算符有点复杂,功能更强大。但首先,让我们看看布尔值会发生什么。

有四种可能的逻辑组合

alert( true || true );   // true
alert( false || true );  // true
alert( true || false );  // true
alert( false || false ); // false

正如我们所见,结果始终为 true,除了两个操作数均为 false 的情况。

如果一个操作数不是布尔值,它将在求值时转换为布尔值。

例如,数字 1 被视为 true,数字 0 被视为 false

if (1 || 0) { // works just like if( true || false )
  alert( 'truthy!' );
}

大多数情况下,OR || 用于 if 语句中,以测试给定条件中的任何条件是否为 true

例如

let hour = 9;

if (hour < 10 || hour > 18) {
  alert( 'The office is closed.' );
}

我们可以传递更多条件

let hour = 12;
let isWeekend = true;

if (hour < 10 || hour > 18 || isWeekend) {
  alert( 'The office is closed.' ); // it is the weekend
}

OR “||” 查找第一个真值

上面描述的逻辑有点经典。现在,让我们引入 JavaScript 的“额外”功能。

扩展算法的工作方式如下。

给定多个 OR 值

result = value1 || value2 || value3;

OR || 运算符执行以下操作

  • 从左到右计算操作数。
  • 对于每个操作数,将其转换为布尔值。如果结果为 true,则停止并返回该操作数的原始值。
  • 如果所有操作数都已计算(即全部为 false),则返回最后一个操作数。

值以其原始形式返回,无需转换。

换句话说,OR || 链返回第一个真值,如果找不到真值,则返回最后一个真值。

例如

alert( 1 || 0 ); // 1 (1 is truthy)

alert( null || 1 ); // 1 (1 is the first truthy value)
alert( null || 0 || 1 ); // 1 (the first truthy value)

alert( undefined || null || 0 ); // 0 (all falsy, returns the last value)

与“纯、经典、仅布尔值的 OR”相比,这导致了一些有趣的用法。

  1. 从变量或表达式的列表中获取第一个真值。

    例如,我们有 firstNamelastNamenickName 变量,它们都是可选的(即可以未定义或具有错误值)。

    让我们使用 OR || 选择具有数据并显示它的变量(如果没有设置,则显示 "Anonymous"

    let firstName = "";
    let lastName = "";
    let nickName = "SuperCoder";
    
    alert( firstName || lastName || nickName || "Anonymous"); // SuperCoder

    如果所有变量都为假,则会显示 "Anonymous"

  2. 短路求值。

    OR || 运算符的另一个特点是所谓的“短路”求值。

    这意味着 || 处理其参数,直到达到第一个真值,然后立即返回该值,甚至不触及其他参数。

    如果操作数不仅仅是一个值,而是一个带有副作用的表达式,例如变量赋值或函数调用,那么此功能的重要性就显而易见了。

    在下面的示例中,仅打印第二条消息

    true || alert("not printed");
    false || alert("printed");

    在第一行中,OR || 运算符在看到 true 后立即停止求值,因此不会运行 alert

    有时,人们使用此功能仅在左侧条件为假时执行命令。

&& (AND)

AND 运算符用两个和号 && 表示

result = a && b;

在经典编程中,如果两个操作数都为真,则 AND 返回 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( 'The time is 12:30' );
}

与 OR 一样,任何值都可以作为 AND 的操作数

if (1 && 0) { // evaluated as true && false
  alert( "won't work, because the result is falsy" );
}

AND “&&” 找到第一个假值

给定多个 AND 值

result = value1 && value2 && value3;

AND && 运算符执行以下操作

  • 从左到右计算操作数。
  • 对于每个操作数,将其转换为布尔值。如果结果为 false,则停止并返回该操作数的原始值。
  • 如果已计算所有操作数(即所有操作数都为真),则返回最后一个操作数。

换句话说,AND 返回第一个假值或最后一个值(如果未找到)。

上述规则与 OR 类似。不同之处在于 AND 返回第一个值,而 OR 返回第一个值。

示例

// if the first operand is truthy,
// AND returns the second operand:
alert( 1 && 0 ); // 0
alert( 1 && 5 ); // 5

// if the first operand is falsy,
// AND returns it. The second operand is ignored
alert( null && 5 ); // null
alert( 0 && "no matter what" ); // 0

我们还可以在一行中传递多个值。看看第一个假值是如何返回的

alert( 1 && 2 && null && 3 ); // null

当所有值都为真时,将返回最后一个值

alert( 1 && 2 && 3 ); // 3, the last one
AND && 的优先级高于 OR ||

AND && 运算符的优先级高于 OR ||

因此,代码 a && b || c && d 本质上与 && 表达式位于括号中相同:(a && b) || (c && d)

不要用 ||&& 替换 if

有时,人们使用 AND && 运算符作为“编写 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,则使用 if,如果我们想要 AND,则使用 &&

! (NOT)

布尔 NOT 运算符用感叹号 ! 表示。

语法非常简单

result = !value;

运算符接受单个参数并执行以下操作

  1. 将操作数转换为布尔类型:true/false
  2. 返回反向值。

例如

alert( !true ); // false
alert( !0 ); // true

有时使用双重 NOT !! 将值转换为布尔类型

alert( !!"non-empty string" ); // true
alert( !!null ); // false

也就是说,第一个 NOT 将值转换为布尔并返回反向值,第二个 NOT 再次反转它。最后,我们得到了一个简单的值到布尔的转换。

还有一种更冗长的方式来执行相同操作——内置 Boolean 函数

alert( Boolean("non-empty string") ); // true
alert( Boolean(null) ); // false

NOT ! 的优先级是所有逻辑运算符中最高的,因此它总是先于 &&|| 执行。

任务

重要性:5

以下代码将输出什么?

alert( null || 2 || undefined );

答案是 2,这是第一个真值。

alert( null || 2 || undefined );
重要性:3

以下代码将输出什么?

alert( alert(1) || 2 || alert(3) );

答案:首先是 1,然后是 2

alert( alert(1) || 2 || alert(3) );

alert 的调用不会返回值。或者,换句话说,它返回 undefined

  1. 第一个 OR || 求值其左操作数 alert(1)。这显示了带有 1 的第一个消息。
  2. alert 返回 undefined,所以 OR 继续到第二个操作数,寻找真值。
  3. 第二个操作数 2 为真,因此执行停止,返回 2,然后由外部警报显示。

不会有 3,因为求值不会到达 alert(3)

重要性:5

这段代码将显示什么?

alert( 1 && null && 2 );

答案:null,因为它是列表中的第一个假值。

alert(1 && null && 2);
重要性:3

这段代码将显示什么?

alert( alert(1) && alert(2) );

答案:1,然后是 undefined

alert( alert(1) && alert(2) );

调用 alert 会返回 undefined(它只显示一条消息,因此没有有意义的返回值)。

因此,&& 会计算左操作数(输出 1),然后立即停止,因为 undefined 是一个假值。而 && 会查找假值并返回该值,因此它完成了。

重要性:5

结果是什么?

alert( null || 2 && 3 || 4 );

答案:3

alert( null || 2 && 3 || 4 );

AND && 的优先级高于 ||,因此它会先执行。

2 && 3 = 3 的结果,因此表达式变为

null || 3 || 4

现在,结果是第一个真值:3

重要性:3

编写一个 if 条件来检查 age 是否介于 1490(包括)之间。

“包括”表示 age 可以达到边界 1490

if (age >= 14 && age <= 90)
重要性:3

编写一个 if 条件来检查 age 是否不介于 1490(包括)之间。

创建两个变体:第一个使用 NOT !,第二个不使用它。

第一个变体

if (!(age >= 14 && age <= 90))

第二个变体

if (age < 14 || age > 90)
重要性:5

哪些 alert 将执行?

if(...) 中表达式的结果是什么?

if (-1 || 0) alert( 'first' );
if (-1 && 0) alert( 'second' );
if (null || -1 && 1) alert( 'third' );

答案:第一个和第三个将执行。

详细信息

// Runs.
// The result of -1 || 0 = -1, truthy
if (-1 || 0) alert( 'first' );

// Doesn't run
// -1 && 0 = 0, falsy
if (-1 && 0) alert( 'second' );

// Executes
// Operator && has a higher precedence than ||
// so -1 && 1 executes first, giving us the chain:
// null || -1 && 1  ->  null || 1  ->  1
if (null || -1 && 1) alert( 'third' );
重要性:3

编写代码,使用 prompt 询问登录名。

如果访问者输入 “Admin”,则提示输入密码;如果输入为空行或 Esc,则显示“已取消”;如果输入其他字符串,则显示“我不认识你”。

密码检查如下

  • 如果它等于“TheMaster”,则显示“欢迎!”,
  • 其他字符串,显示“密码错误”,
  • 对于空字符串或取消的输入,显示“已取消”

架构

请使用嵌套 if 块。注意代码的整体可读性。

提示:向提示传递空输入会返回一个空字符串 ''。在提示期间按 ESC 会返回 null

运行演示

let userName = prompt("Who's there?", '');

if (userName === 'Admin') {

  let pass = prompt('Password?', '');

  if (pass === 'TheMaster') {
    alert( 'Welcome!' );
  } else if (pass === '' || pass === null) {
    alert( 'Canceled' );
  } else {
    alert( 'Wrong password' );
  }

} else if (userName === '' || userName === null) {
  alert( 'Canceled' );
} else {
  alert( "I don't know you" );
}

请注意 if 块内的垂直缩进。从技术上讲,它们不是必需的,但可以使代码更具可读性。

教程地图

评论

评论前请先阅读此内容…
  • 如果你有改进建议,请 提交 GitHub 问题 或拉取请求,而不是进行评论。
  • 如果你无法理解文章中的某些内容,请详细说明。
  • 要插入几行代码,请使用 <code> 标记,对于多行,请将其包装在 <pre> 标记中,对于 10 行以上,请使用沙盒 (plnkrjsbincodepen…)