精讲 JavaScript 逻辑运算符:与、或、非

简介: 精讲 JavaScript 逻辑运算符:与、或、非

640.png


逻辑运算符


JavaScript 里有三个逻辑运算符:||(或),&&(与),!(非)。

虽然他们被称为“逻辑”运算符,但这些运算符却可以被应用于任意类型的值,而不仅仅是布尔值。他们的结果也同样可以是任意类型。


让我们来详细看一下。


||(或)


两个竖线符号表示了“或”运算:


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) { // 工作原理相当于 if( true || false )
  alert( 'truthy!' );
}


大多数情况,逻辑或 || 会被用在 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.' ); // 是周末
}


或运算寻找第一个真值


上文提到的逻辑处理多少有些传统了。下面让我们看看 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(所有的转化结果都是 false,返回最后一个值)


与“纯粹的、传统的、仅仅处理布尔值的或运算”相比,这个规则就引起了一些很有趣的用法。


  1. 获取变量列表或者表达式的第一个真值。
    假设我们有几个变量,它们可能包含某些数据或者是 null/undefined。我们需要选出第一个包含数据的变量。
    我们可以这样应用或运算 ||


let currentUser = null;
let defaultUser = "John";
let name = currentUser || defaultUser || "unnamed";
alert( name ); // 选出了 “John” — 第一个真值


  1. 如果 currentUserdefaultUser 都是假值,那么结果就是 "unnamed"
  2. 短路取值。
    操作数不仅仅可以是值,还可以是任意表达式。或运算会从左到右计算并测试每个操作数。当找到第一个真值,计算就会停止,并返回这个值。这个过程就叫做“短路取值”,因为它尽可能地减少从左到右计算的次数。
    当表达式作为第二个参数并且有一定的副作用(side effects),比如变量赋值的时候,短路取值的情况就清楚可见。
    如果我们运行下面的例子,x 将不会被赋值:


let x;
true || (x = 1);
alert(x); // undefined,因为 (x = 1) 没有被执行


  1. 如果第一个参数是 false,或运算将会继续,并计算第二个参数,也就会运行赋值操作。


let x;
false || (x = 1);
alert(x); // 1


  1. 赋值操作只是一个很简单的情况。可能有副作用,如果计算没有到达,副作用就不会发生。
    正如我们所见,这种用法是“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) { // 作为 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,最后一个值


与运算 && 在或操作符 || 之前执行


与运算 && 的优先级比或运算 || 要高。

所以代码 a && b || c && d 完全跟 && 表达式加了括号一样:(a && b) || (c && d)

就像或运算一样,与运算 && 有时候能够代替 if

例如:


let x = 1;
(x > 0) && alert( 'Greater than zero!' );


&& 右边的代码只有运算抵达到那里才能被执行。也就是,当且仅当 (x > 0) 返回了真值。

所以我们基本可以类似地得到:


let x = 1;
if (x > 0) {
  alert( 'Greater than zero!' );
}


&& 的代码变体看上去更短。但是 if 的含义更明显,可读性也更高。

所以建议是根据目的选择代码的结构。需要条件判断就用 if,需要与运算就用 &&


!(非)


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


语法相当简单:


result = !value;


操作符接受一个参数,并按如下运作:

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

例如:


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


非运算符 ! 的优先级在所有逻辑运算符里面最高,所以它总是在 &&|| 前执行。


作业题


先自己做题目再看答案。


1. 或运算的结果是什么?


重要程度:⭐️⭐️⭐️⭐️⭐️


如下代码将会输出什么?


alert( null || 2 || undefined );


答案:

结果是 2,这是第一个真值。


alert( null || 2 || undefined );


2. 或运算和 alerts 的结果是什么?


重要程度:⭐️⭐️⭐

下面的代码将会输出什么?


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

答案:


首先是 1,然后是 2


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

alert 的调用没有返回值。或者说返回的是 undefined


  1. 第一个或运算 || 对它的左值 alert(1) 进行了计算。这就显示了第一条信息 1
  2. 函数 alert 返回了 undefined,所以或运算继续检查第二个操作数以寻找真值。
  3. 第二个操作数 2 是真值,所以执行就中断了。2 被返回,并且被外层的 alert 显示。

这里不会显示 3,因为运算没有抵达 alert(3)


3. 与操作的结果是什么?


重要程度:⭐️⭐️⭐️⭐️⭐️

下面这段代码将会显示什么?


alert( 1 && null && 2 );


答案:

null,因为它是列表中第一个假值。


alert( 1 && null && 2 );


4. 与运算连接的 alerts 的结果是什么?

重要程度:⭐️⭐️⭐

这段代码将会显示什么?


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 );

与运算 && 的优先级比 || 高,所以它第一个被执行。


结果是 2 && 3 = 3,所以表达式变成了:


null || 3 || 4


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

6. 检查值是否位于范围区间内


重要程度:⭐️⭐️⭐

写一个“if”条件句来检查 age 是否位于 1490 的闭区间。

“闭区间”意味着,age 的值可以取 1490

答案:


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


7. 检测值是否位于范围之外

重要程度:⭐️⭐️⭐

写一个 if 条件句,检查 age 是否不位于 14 到 90 的闭区间。

创建两个表达式:第一个用非运算 !,第二个不用。

答案:

第一个表达式:


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


第二个表达式:


if (age < 14 || age > 90)


8. 一个关于 "if" 的问题

重要程度:⭐️⭐️⭐️⭐️⭐️

下面哪一个 alert 将会被执行?

if(...) 语句内表达式的结果是什么?


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


答案:

第一个和第三个将会被执行。

详解:


// 执行。
// -1 || 0 的结果为 -1,真值
if (-1 || 0) alert( 'first' );
// 不执行。
// -1 && 0 = 0,假值
if (-1 && 0) alert( 'second' );
// 执行
// && 运算的优先级比 || 高
// 所以 -1 && 1 先执行,给出如下运算链:
// null || -1 && 1  ->  null || 1  ->  1
if (null || -1 && 1) alert( 'third' );


9. 登陆验证


重要程度:⭐️⭐️⭐


实现使用 prompt 进行登陆校验的代码。

如果访问者输入 "Admin",那么使用 prompt 引导获取密码,如果输入的用户名为空或者按下了 key:Esc 键 —— 显示 "Canceled",如果是其他字符串 —— 显示 "I don't know you"。


密码的校验规则如下:

  • 如果输入的是 "TheMaster",显示 "Welcome!",
  • 其他字符串 —— 显示 "Wrong password",
  • 空字符串或取消了输入,显示 "Canceled."。

流程图:

ecee7ca52a29a74272dacfe42750eab6.jpg

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

提示:将空字符串输入,prompt 会获取到一个空字符串 ''。Prompt 运行过程中,按下 key:ESC 键会得到 null


答案:


代码如下:


let userName = prompt("Who's there?", '');
if (userName == 'Admin') {
  let pass = prompt('Password?', '');
  if (pass == 'TheMaster') {
    alert( 'Welcome!' );
  } elseif (pass == '' || pass == null) {
    alert( 'Canceled' );
  } else {
    alert( 'Wrong password' );
  }
} elseif (userName == '' || userName == null) {
  alert( 'Canceled' );
} else {
  alert( "I don't know you" );
}


请注意 if 块中水平方向的缩进。技术上是非必需的,但会增加代码的可读性。

目录
相关文章
|
2月前
|
JavaScript 前端开发
JavaScript 比较 和 逻辑运算符
JavaScript 比较 和 逻辑运算符
19 6
|
3月前
|
JavaScript 前端开发
JavaScript基础&实战(2)js中的强制类型转换、运算符、关系运算符、逻辑运算符、条件运算符
这篇文章详细介绍了JavaScript中的强制类型转换、运算符(包括算术、逻辑、条件、赋值和关系运算符)的使用方法和优先级规则。
JavaScript基础&实战(2)js中的强制类型转换、运算符、关系运算符、逻辑运算符、条件运算符
|
3月前
|
JavaScript 前端开发
深入JavaScript的逻辑运算符
深入JavaScript的逻辑运算符
|
11月前
|
JavaScript
JS中的逻辑运算符&&、||
1、JS中的||符号: 运算方法:
31 0
|
JavaScript 前端开发
JavaScript 比较 和 逻辑运算符
JavaScript 比较 和 逻辑运算符
50 0
|
前端开发
前端知识案例15-javascript基础语法-逻辑运算符
前端知识案例15-javascript基础语法-逻辑运算符
71 0
前端知识案例15-javascript基础语法-逻辑运算符
|
JavaScript PHP Python
PHP、JS、Python逻辑运算符||和位运算符|
PHP、JS、Python逻辑运算符||和位运算符|
117 0
PHP、JS、Python逻辑运算符||和位运算符|
|
JavaScript PHP Python
PHP、JS、Python逻辑运算符||和位运算符|
PHP、JS、Python逻辑运算符||和位运算符|
109 0
|
JavaScript 前端开发
07-JavaScript基础-关系运算符和逻辑运算符
关系运算符 为什么要学习关系运算符? 默认情况下,我们在程序中写的每一句正确代码都会被执行。但很多时候,我们想在某个条件成立的情况下才执行某一段代码 这种情况的话可以使用条件语句来完成,但是学习条件语句之前,我们先来看一些更基础的知识:如何判断一个条件成不成立。
1024 0
|
4月前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp的客户关系管理系统附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp的客户关系管理系统附带文章源码部署视频讲解等
97 2