JS 教程之 JavaScript 运算符以及流程控制

前面我们已经解读了 JS 中变量以及基本数据类型等基本概念,本文接着来看 JavaScript 中的运算符以及程序流程控制语句,这是一个 JavaScript 程序实现的必要部分。

JS 中的运算符

开始后续的流程控制学习之前,我们需要系统的认识一下 JavaScript 中的运算符(也称为操作符)。

我们先来看一个简单的例子:

1
2
> 4 + 5
9

其中,45 被称为 操作数+ 被称之为 运算符(操作符),它们共同构成一个 表达式

可以看到,JS 中的表达式类似于数学上的数学表达式,由操作数以及操作符(运算符)组合而成。

[1] >>> 特殊概念

–> 优先级 & 结合性

JS 中的运算符,等价于数学中的运算符,也是有优先级,和结合性的概念的。

这也就是说 >>> 当一个表达式中出现多种操作符时,执行的先后顺序不仅要遵守操作符优先级规定,还要受操作符结合性的约束,以便确定是自左向右进行运算?还是自右向左进行运算?

–> 操作数

操作数是指 >>> 运算符进行运算时,所操作(依赖)的数据。

[2] >>>运算符分类

JavaScript 语言中最基本的运算符可归纳为以下 5 大类:

  1. 赋值运算符
  2. 算术运算符
  3. 关系(比较)运算符
  4. 逻辑运算符
  5. 位运算符

并且,根据【操作数的数量】又衍生出了:单目运算符、双目运算符、三目运算符 的概念(看到这样的表述不要疑惑)。


JS 运算符详解

这一小节将详细解读上面提到的 5 种 JS 基本运算符用法:

赋值运算符

前面的变量章节部分中提到过 >>> 变量声明时(后),可以使用赋值运算符为变量进行赋值。

赋值运算符就是指,为 变量或常量 指定数值(赋值) 的符号。使用很简单,其语法格式如下所示:

1
变量名称 = 值(或表达式)

它是一个双目运算符。其左边的操作数必须是变量,不能是常量值或表达式;右侧可以为字面值,或表达式。

需要注意的是 >>> 不要将赋值运算符与相等运算符 “==” 混淆。

示例代码如下:

1
2
> var i = 1;
> var j = i + 2;

事实上,JS 中还有一种 扩展赋值运算符,它是由其它基本运算符和赋值运算符结合而成。例如算术赋值运算符(+= && -= && *= 等),以及位赋值运算符(<<= && >>= 等)。通常情况下,只要能使用扩展后的赋值运算符,都推荐使用这种赋值运算符。

关于扩展赋值运算符的使用,将在其结合运算符中进行说明。


算术运算符

算术运算符的功能是 >>> 对变量与/或字面量(变量与变量、变量与字面量、字面量与字面量)进行算术运算。

JS 中支持如下的算术运算:

运算符 说明 范例 结果
+ 正号 +3 3
- 负号 -4 -4
+ 加法运算 5 + 5 10
- 减法运算 10 - 5 5
* 乘法运算 5 * 2 10
/ 除法运算 10 / 3 3.333
% 取模(余)运算 10 % 3 1
++ 自增运算 a = 2; a++ 3
-- 自减运算 a = 10; a-- 9

这里为了方便记忆,特将算术运算分为三类:

  1. 基本算术运算符:+(加) -(减) *(乘) /(除)%(取模/取余);
  2. 算术赋值运算符:+=(加法赋值)-=(减法赋值)*=(乘法赋值)/=(除法赋值)%=(取模赋值);
  3. 算术单目运算符:+(正) -(负) ++(自增) --(自减)。

[1] >>> 基本算术运算符

JS 算术运算符中,最基本的算术运算就是:

1
+(加) -(减) *(乘) /(除)%(取模/取余)

上述算术运算,和我们平常接触的数学运算具有相同的含义。

加法运算】示例代码如下 >>>

1
2
3
4
5
> var aNum = 21;
> var bNum = 10;
> cNum = aNum + bNum;
> console.log("The Value of cNum:", cNum);
The Value of cNum: 31

+ 用于数值(Number)类型时表示加法运算;但是当 + 用于字符串类型时表示连接运算(连接运算符),请参照 JavaScript 中的原始 String 类型中的说明。

+ 除了用作加法运算符之外,还可以作为正数(正号)的标志(例如:+2),一般缺省。

减法运算】示例代码如下 >>>

1
2
3
4
> var aNum = 21, bNum = 10;
> var cNum = aNum - bNum;
> console.log("The Value of cNum:", cNum);
The Value of cNum: 11

- 除了可以用作减法运算之外,还可以用作求负(负号)运算(正数变负数,负数变正数),即取相反数。

乘法运算】示例代码如下 >>>

1
2
3
4
> var aNum = 21, bNum = 10;
> var cNum = aNum * bNum;
> console.log("The Value of cNum:", cNum);
The Value of cNum: 210

需要注意的是,JS 中 * 仅用于数值相乘;而有些编程语言中,* 还用于进行序列(字符串)的重复运算,用于将某个序列复制几份并连接起来。

除法运算】示例代码如下 >>>

1
2
3
4
> var aNum = 21, bNum = 10;
> var cNum = aNum / bNum;
> > console.log("The Value of cNum:", cNum);
The Value of cNum: 2.1

需要注意的是,JS 进行除法运算时,除数为 0 时不会产生错误(ZeroDivisionError),而是输出 Infinity(正无穷大)。

取模(取余)运算】示例代码如下 >>>

1
2
3
4
> var aNum = 21, bNum = 10;
> var cNum = aNum % bNum;
> > console.log("The Value of cNum:", cNum);
The Value of cNum: 1

[2] >>> 算术赋值运算符

算术赋值运算符只是一种(赋值和算术运算符结合的)简写形式,一般用于变量自身的变化。

上述的每一种基本算术运算符,都有一种对应的和赋值符结合的简写形式:

运 算 符 名 称 例 子 等价于
+= 加法赋值 a += b + 3 a = a + b + 3
-= 减法赋值 a -= b a = a - b
*= 乘法赋值 a *= b a = a*b
/= 除法赋值 a /= b a = a/b

[3] >>> 算术单目运算符

算术操作符中,单目运算符有 4 个,分别表示:+(正) -(负) ++(自增) --(自减)。

其中,+(正)&& -(负)较为简单,就是数学上的含义,不做过多说明。下面重点来看自增、自减的使用。

自增 && 自减 >>> 使用原则:

  • 自增/自减只能作用于变量,不允许对字面量、表达式等进行操作;
  • 自增/自减运算作用于变量自身加/减 1放在操作数的 前面或后面 都是允许的

3.1 –> 自增 & 自减

i++(自增)i--(自减):在变量 i 原来的基础上,增加 1 或者减少 1

1
2
3
4
5
6
7
8
9
10
11
// 自增:
> var i = 4;
> i++;
> console.log("The Value of i:", i);
The Value of i: 5

// 自减:
> var j = 4;
> j--;
> console.log("The Value of j:", j);
The Value of j: 3

3.2 –> 前后置的区别

以 ++(自增)为例,-- 同理。

1
2
3
4
5
6
> var i = 4;
> i++; // 先取值,再运算
4

> ++i; // 先运算,再取值
6

具体示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
> var i = 5;
> console.log(i++); // 输出 5
5
> console.log(i); // 输出 6
6

> var j = 5;
> console.log(++j); // 输出 6
6
> console.log(j); // 输出 6
6

思考一下:下面的 j 是 多少?

1
2
> var i = 1;
> var j = ++i + i++ + ++i + ++i + i++; // 2 + 2(3) + 4 + 5 + 5 = 18

关系运算符

关系操作符(relational operators)也可以称为:“比较操作符”,用来比较判断两个变量或字面量的大小关系。

关系运算的结果都是 Boolean 型的。当操作符对应的大小关系成立时,运算结果是 true,否则是 false

JS 中支持的比较操作符列表如下:

运算符 说明 范例 结果
== 等于,如果 == 两边的值相等,则返回 True;否则返回 False 4 == 4 true
!= 不相等 (等价于数学中的 ≠),如果 != 两边的值不相等,则返回 True;否则返回 False 4 != “4” false
=== 等值等型,如果 === 两边的操作数的值以及数据类型都相同,则返回 True;有一个不同则返回 False 4 == “4” false
!== 不等值或不等型,如果 !== 两边的操作数的值以及数据类型至少有一个不同,则返回 True;否则返回 False 4 !== “4” true
< 小于,如果 < 前面的值小于后面的值,则返回 True,否则返回 False 4 < 3 false
> 大于,如果 > 前面的值大于后面的值,则返回 True,否则返回 False 4 > 3 true
<= 小于等于(等价于数学中的 ≤),如果 <= 前面的值小于或者等于后面的值,则返回 True,否则返回 False 4 <= 3 false
>= 大于等于(等价于数学中的 ≥),如果 >= 前面的值大于或者等于后面的值,则返回 True,否则返回 False 4 >= 3 true

这里为了方便记忆,特将关系运算分为三类:

  1. 大小关系检测:<(小于) <=(小于等于) >(大于) >=(大于等于);
  2. 等值关系检测:==(等于) !=(不相等);
  3. 相同关系检测:===(等值等型) !==(不等值或不等型)。

[1] >>> 大小关系检测

大小关系检测时,操作数的比较规则:

  • 数值与数值比较 >>> 直接比较它们的代数值;
  • 仅一个操作数是数值 >>> 将另一个操作数转化为数值后,比较它们的代数值;
  • 字符串与字符串比较 >>> 逐字符比较它们的 Unicode 数值;
  • 字符串与非数值比较 >>> 将非数值操作数转化为字符串后,进行比较;
  • 只要与 NaN 比较 >>> 均返回 false;
  • 操作数既非数值也非字符串 >>> 转化为数值或字符串后进行比较;
  • 操作数无法被转化为数值或字符串 >>> 均返回 false。

关于操作数的类型转化,你可以参见博文系列中的 JS 中数据类型转换章节。

[2] >>> 等值关系检测

等值关系检测时,操作数的比较规则:

  • 数值与/或字符串比较规则同上;
  • null == undefined(两者相等),比较前不进行任何转换(相等比较中,null && undefined 允许被转换为其他类型的值。);
  • NaN 与任何值都不相等,包括其本身(即:NaN != NaN);
  • 操作数都是对象时,则比较引用地址,引用地址相同,则相等;否则不等。

特殊操作数相等比较实例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
console.log("1" == 1);  // 返回 true
console.log(true == 1); // 返回 true
console.log(false == 0); // 返回 true

console.log(null == 0); // 返回 false
console.log(undefined == 0); // 返回 false
console.log(undefined == null); // 返回 true

console.log(NaN == "NaN"); // 返回 false
console.log(NaN == 0); // 返回 false
console.log(NaN == NaN); // 返回 false
console.log(NaN != NaN); // 返回 true

var aArray = [1, 2];
var bArray = [1, 2];
console.log(aArray == bArray); // 引用地址不同,返回 false
var cArray = aArray;
console.log(aArray == cArray); // 引用地址相同,返回 true

[3] >>> 相同关系检测

相同关系检测时,操作数的比较规则:

  • 值类型间比较 >>> 数据类型相同且数值也相等,才相同;
  • 值类型与引用类型比较 >>> 肯定不相同;
  • 引用类型间比较 >>> 比较引用地址,引用地址相同,则相同。

特殊操作数相等比较实例代码如下:

1
2
3
4
5
6
7
8
9
console.log(null === undefined);  // 返回 false
console.log(0 === "0"); // 返回 false
console.log(0 === false); // 返回 false

var a = {};
var b = {};
console.log(a === b); // 返回 false
var c = a;
console.log(a === c); // 返回 true

逻辑运算符

逻辑运算又称为 布尔代数运算,就是布尔值的运算。JS 中支持的逻辑运算符如下:

  • a && b:等价于数学中的 “且”,a 和 b 两个表达式都真为真,有假即假;
  • a || b:等价于数学中的 “或”,a 和 b 两个表达式有真即真,都假为假;
  • !a:等价于数学中的 “非”(相当于对 a 取反),如果 a 为真,那么 !a 的结果为假;如果 a 为假,那么 !a 的结果为真。

[1] >>> 短路逻辑特性

短路逻辑概念的引入,是为了优化逻辑表达式的计算方式,从而提高程序效率(实际编程中,应优先考虑使用短路逻辑)。

于是,编程语言设计中对逻辑运算符又进一步细分:

  1. “且/与” >>> 逻辑与(&)短路与(&&)
  2. “或” >>> 逻辑或(|)短路或(||)

对于 短路与(&&)>>> 若第一个表达式是 false,后续的就不进行运算了(有假即假);短路或(||)>>> 若第一个表达式是 true,后续的就不进行运算了(有真即真)。而对于逻辑与(&)和 逻辑或(|)所有表达式均需要计算(效率较低)。

需要注意的是,JS 中的逻辑运算符就是优化计算的短路与(&&)和 短路或(||),不支持另外单独的的逻辑与、或运算符。


[2] >>> 操作关系表达式

由于关系表达式的返回结果都是 Boolean 型的,故:

一般情况下,逻辑运算符会把多个 关系表达式(返回布尔值) 组合成一个逻辑表达式,以判断整个逻辑表达式是否成立,返回的结果是 true 或 false。

1
2
3
4
> var ageNum = 23;
> var heightNum = 178;
> console.log("是否符合报考飞行员的条件:", ageNum >= 18 && ageNum <= 30 && heightNum >= 170 && heightNum <= 185);
是否符合报考飞行员的条件: true

[3] >>> 更一般的表达式

前面在介绍原始 Boolean 类型转换时,提到过 布尔值(true && false)可以直接参与逻辑表达式运算。且:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 逻辑表达式中以下值会被认为是 False:
// 为零的数:0 or -0 or 0.0 or NaN;
// 空字符串:'',"";
// 空对象:null;
// 未定义:undefined;
// 其他的值(非空字符串、非零数值、非空对象)都认为是 True(注意:[] && {})。
// 你可以使用 `Boolean(obj)` 对 JS 中的所有对象进行真假值的测试:包括字符串、数值、null、undefined、obj、表达式等。
> Boolean(null)
false
> Boolean(undefined);
false
> Boolean([]);
true
> Boolean({});
true

> Boolean(true && "test");
true
> Boolean(true && NaN);
false
> Boolean(false || 1.25);
true
> Boolean(false || "");
false

也就是说,逻辑运算符可以用来操作任何类型的表达式,不管表达式返回是不是 Boolean 类型的。


[4] >>> 逻辑运算本质

并且,通过逻辑运算的结果也不一定是 Boolean 类型,它也可以是任意类型。

对于 短路与(&&),两边的值都为假时最终结果才为假,有假即假。所以 JS 按照下面的规则执行短路与运算:

  • 如果左边表达式的值可转换为假(false),那么就不用计算右边表达式的值了(不管右边表达式的值是什么,都不会影响最终结果,为假),此时会返回左边表达式的值;
  • 如果左边表达式的值可转换为真(true),那么最终值是不能确定的,短路与(&&)会继续计算右边表达式的值,并返回右边表达式的值。

对于 短路或(||),情况是类似的,两边的值都为假时最终结果才为假,有真即真。所以 JS 按照下面的规则执行短路与运算:

  • 如果左边表达式的值可转换为真(true),那么就不用计算右边表达式的值了(不管右边表达式的值是什么,都不会影响最终结果,为真),此时会返回左边表达式的值;
  • 如果左边表达式的值可转换为假(false),那么最终值是不能确定的,短路或(||)会继续计算右边表达式的值,并返回右边表达式的值。

使用代码验证上面的结论:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 逻辑表达式中以下值会被认为是 False:
// 为零的数:0 or -0 or 0.0 or NaN;
// 空字符串:'',"";
// 空对象:null;
// 未定义:undefined;
// 其他的值(非空字符串、非零数值、非空对象)都认为是 True(注意:Infinity && [] && {})。
// 你可以使用 `Boolean(obj)` 对 JS 中的所有对象进行真假值的测试:包括字符串、数值、null、undefined、obj、表达式等。
str = "hello JS";

console.log("----False and xxx-----");
console.log(false && str);
console.log("----True and xxx-----");
console.log(true && str);

console.log("----False or xxx-----");
console.log(false || str);
console.log("----True or xxx-----");
console.log(true || str);

运行看一下:

1
2
3
4
5
6
7
8
----False and xxx-----
false
----True and xxx-----
hello JS
----False or xxx-----
hello JS
----True or xxx-----
true

[5] >>> 取反(!)

真变为假,假变为真。示例代码如下:

1
2
3
4
5
> var isTrue = true;
> console.log(isTrue);
true
> console.log(!isTrue);
false

位运算符

编程语言中的位运算(bitwise operators),表示 按 数值 在内存中的每个二进制位(bit)进行计算,也称为 按位运算

也就是说,JS 中可以直接对 数值类型数据 的二进制位进行操作,其操作数和运算结果都是数值型值。

JS 中支持的位运算操作符列表如下:

运算符 描述 示例
& 按位与:参与运算的两个数值,如果对应的二进制位都为 1,则该二进制位的结果为 1;否则为 0 5 & 1 等同于 0101 & 0001,结果为 0001,十进制结果为 1
| 按位或:参与运算的两个数值,如果对应的二进制位至少有一个为 1,则该二进制位的结果为 1;否则为 0 5 | 1 等同于 0101 | 0001,结果为 0101,十进制结果为 5
^ 按位异或:参与运算的两个数值,如果对应的二进制位互异时,则该二进制位的结果为 1;相同结果为 0 5 ^ 1 等同于 0101 ^ 0001,结果为 0100,十进制结果为 4
~ 按位非:对某个数值的所有二进制位按位取反,即 1 转换为 0;0 转换为 1 ~5 等同于 ~0101,结果为 1010,十进制结果为 -6
<< 按位左移:把 “<<” 左边的操作数各二进位全部左移若干位,”<<” 右边的数用来指定移动的位数;高位丢弃,低位补 0 5 << 1 等同于 0101 << 1,结果为 1010,十进制结果为 10
>> 按位右移(有符号右移):把 “>>” 左边的操作数的各二进位全部右移若干位,”>>” 右边的数指定移动的位数;拷贝最左侧的符号位来填充左侧 5 >> 1 等同于 0101 >> 1,结果为 0010,十进制结果为 2
>>> 按位右移零(无符号右移):把 “>>>” 左边的操作数的各二进位全部右移若干位,”>>>” 右边的数指定移动的位数;最左侧补 0 5 >>> 1 等同于 0101 >>> 1,结果为 0010,十进制结果为 2

这里为了方便记忆,特将位运算分为三类:

  1. 位逻辑运算符:&(按位与)、|(按位或)、~(按位非)和 ^(按位异或)
  2. 位移运算符:<<(按位左移)、>>(有符号按位右移)、>>>(无符号按位右移)
  3. 位赋值运算符:&=(按位与赋值)、|=(按位或赋值)、^=(按位异或赋值)、<<=(按位左移赋值)、>>=(有符号按位右移赋值)以及 >>>=(无符号按位右移赋值)。

[1] >>> 位逻辑运算符


三目(条件)运算符


其它运算符

Author

Waldeinsamkeit

Posted on

2019-02-05

Updated on

2023-01-16

Licensed under

You need to set install_url to use ShareThis. Please set it in _config.yml.

Comments

You forgot to set the shortname for Disqus. Please set it in _config.yml.