Web/04-JavaScript基础/08-运算符.md
2020-06-12 15:51:38 +08:00

610 lines
15 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

我们在本文件夹的第 02 篇里讲到了JS中**变量**的概念本篇文章讲一下**运算符**和表达式
## 运算符的定义和分类
### 运算符的定义
**运算符**也叫操作符是一种符号通过运算符可以对一个或多个值进行运算并获取运算结果
**表达式**由数字运算符变量的组合组成的式子
表达式最终都会有一个运算结果我们将这个结果称为表达式的**返回值**
比如`+``*``/``(` 都是**运算符**`3+5/2`则是**表达式**
比如typeof 就是运算符可以来获得一个值的类型它会将该值的类型以**字符串**的形式返回返回值可以是 numberstringbooleanundefinedobject
### 运算符的分类
JS 中的运算符分类如下
- 算数运算符
- 自增/自减运算符
- 一元运算符
- 逻辑运算符
- 赋值运算符
- 比较运算符
- 三元运算符条件运算符
下面来逐一讲解
## 算数运算符
**算术运算符**用于执行两个变量或值的算术运算
常见的算数运算符有以下几种
| 运算符 | 描述 |
| :---------------- | :-------: |
| + | 字符串连接 |
| - | |
| * | |
| / | |
| % | 获取余数取余取模 |
**求余的举例**
假设用户输入345怎么分别得到345这三个数呢
**答案**
```
得到3的方法345 除以100得到3.45然后取整得到3。即parseInt(345/100)
得到4的方法345 除以100余数是45除以10得到4.5取整。即parseInt(345 % 100 / 10)
得到5的方法345 除以10余数就是5。即345 % 10
```
### 算数运算符的运算规则
1先算乘除后算加减
2小括号`( )`能够影响计算顺序且可以嵌套没有中括号没有大括号只有小括号
3百分号取余只关心余数
举例1(取余)
```javascript
console.log(3 % 5);
```
输出结果为3
举例2注意运算符的优先级
```javascript
var a = 1 + 2 * 3 % 4 / 3;
```
结果分析
原式 = 1 + 6 % 4 / 3 = 1 + 2 / 3 = 1.66666666666666
**补充**关于算数运算符的注意事项详见上一篇文章里的**数据类型转换**的知识点
### 浮点数运算的精度问题
浮点数值的最高精度是 17 位小数但在进行算术计算时会丢失精度导致计算不够准确比如
```javascript
console.log(0.1 + 0.2); // 运算结果不是 0.3,而是 0.30000000000000004
console.log(0.07 * 100); // 运算结果不是 7而是 7.000000000000001
```
因此**不要直接判断两个浮点数是否相等**
## 自增和自减
### 自增 `++`
自增分成两种`a++``++a`
1一个变量自增以后原变量的值会**立即**自增1也就是说无论是 `a++` 还是`++a`都会立即使原变量的值自增1
2**我们要注意的是**`a`是变量`a++``++a`**表达式**
那这两种自增有啥区别呢区别是`a++` `++a`的值不同也就是说表达式的值不同
- `a++`这个表达式的值等于原变量的值a自增前的值你可以这样理解先把 a 的值赋值给表达式然后 a 再自增
- `++a`这个表达式的值等于新值 a自增后的值 你可以这样理解a 先自增然后再把自增后的值赋值给表达式
### 自减 `-- `
原理同上
开发时大多使用后置的自增/自减并且代码独占一行例如`num++`或者 `num--`
### 代码举例
```javascript
var n1 = 10;
var n2 = 20;
var result1 = n1++;
console.log(n1); // 11
console.log(result1); // 10
result = ++n1;
console.log(n1); //12
console.log(result); //12
var result2 = n2--;
console.log(n2); // 19
console.log(result2); // 20
result2 = --n2;
console.log(n2); // 18
console.log(result2); // 18
```
## 一元运算符
一元运算符只需要一个操作数
常见的一元运算符如下
### typeof
typeof就是典型的一元运算符因为后面只跟一个操作数
举例如下
```javascript
var a = '123';
console.log(typeof a); // 打印结果string
```
### 正号 `+`
1正号不会对数字产生任何影响比如说`2``+2`是一样的
2我们可以对一个其他的数据类型使用`+`来将其转换为number重要的小技巧比如
```javascript
var a = true;
a = +a; // 注意这行代码的一元运算符操作
console.log('a' + a);
console.log(typeof a);
console.log('-----------------');
var b = '18';
b = +b; // 注意这行代码的一元运算符操作
console.log('b' + b);
console.log(typeof b);
```
打印结果
```
a1
number
-----------------
b18
number
```
### 负号 `-`
负号可以对数字进行取反
## 逻辑运算符
逻辑运算符有三个
- `&&` 两个都为真结果才为真
- `||` 只要有一个是真结果就是真
- `!` 对一个布尔值进行取反
注意能参与逻辑运算的都是布尔值
**连比的写法**
来看看逻辑运算符连比的写法
举例1
```javascript
console.log(3 < 2 && 2 < 4);
```
输出结果为false
举例2判断一个人的年龄是否在18~65岁之间
```javascript
const a = prompt('请输入您的年龄');
if (a >= 18 && a < 65) {
alert('可以上班');
} else {
alert('准备退休');
}
```
PS上面的`a>=18 && a<= 65`千万别想当然地写成` 18<= a <= 65`没有这种语法
### 非布尔值的与或运算重要
> 之所以重要是因为在实际开发中我们经常用这种代码做容错处理或者兜底处理
非布尔值进行**与或运算**会先将其转换为布尔值然后再运算但返回结果是**原值**比如说
```javascript
var result = 5 && 6; // 运算过程true && true;
console.log('result' + result); // 打印结果6也就是说最后面的那个值。
```
上方代码可以看到虽然运算过程为布尔值的运算但返回结果是原值
那么返回结果是哪个原值呢我们来看一下
**与运算**的返回结果以多个非布尔值的运算为例
- 如果第一个值为false则执行第一条语句并直接返回第一个值不会再往后执行
- 如果第一个值为true则继续执行第二条语句并返回第二个值如果所有的值都为true则返回的是最后一个值
**或运算**的返回结果以多个非布尔值的运算为例
- 如果第一个值为true则执行第一条语句并直接返回第一个值不会再往后执行
- 如果第一个值为false则继续执行第二条语句并返回第二个值如果所有的值都为false则返回的是最后一个值
实际开发中我们经常是这样来做容错处理
当前端成功调用一个接口后返回的数据为 result 对象这个时候我们用变量 a 来接收 result 里的图片资源通常的写法是这样的
```javascript
if (result.resultCode == 0) {
var a = result && result.data && result.data.imgUrl || 'http://img.smyhvae.com/20160401_01.jpg';
}
```
上方代码的意思是获取返回结果中的`result.data.imgUrl`这个图片资源如果返回结果中没有 `result.data.imgUrl` 这个字段就用 `http://img.smyhvae.com/20160401_01.jpg` 作为**兜底**图片这种写法在实际开发中经常用到
### 非布尔值的 `!` 运算
非布尔值进行**与或运算**会先将其转换为布尔值然后再运算但返回结果是**布尔值**
举例
```javascript
let a = 10;
a = !a
console.log(a); // false
console.log(typeof a); // boolean
```
### 短路运算的妙用重要
> 下方举例中的写法技巧在实际开发中经常用到这种写法是一种很好的容错容灾降级方案需要多看几遍
1JS中的`&&`属于**短路**的与
- 如果第一个值为false则不会执行后面的内容
- 如果第一个值为 true则继续执行第二条语句并返回第二个值
举例
```javascript
const a1 = 'qianguyihao';
//第一个值为true会继续执行后面的内容
a1 && alert('看 a1 出不出来'); // 可以弹出 alert 框
const a2 = undefined;
//第一个值为false不会继续执行后面的内容
a2 && alert('看 a2 出不出来'); // 不会弹出 alert 框
```
2JS中的`||`属于**短路**的或
- 如果第一个值为true则不会执行后面的内容
- 如果第一个值为 false则继续执行第二条语句并返回第二个值
举例
```js
const result; // 请求接口时,后台返回的内容
let errorMsg = ''; // 前端的文案提示
if (result && result.retCode != 0) {
// 接口返回异常码时
errorMsg = result.msg || '活动太火爆,请稍后再试'; // 文案提示信息,优先用 接口返回的msg字段其次用 '活动太火爆,请稍后再试' 这个文案兜底。
}
if (!result) {
// 接口挂掉时
errorMsg = '网络异常,请稍后再试';
}
```
## 赋值运算符
可以将符号右侧的值赋值给符号左侧的变量
举例
- `=` 直接赋值比如 `var a = 5`
- `+=`a += 5 等价于 a = a + 5
- `-=`a -= 5 等价于 a = a - 5
- `*=`a *= 5 等价于 a = a * 5
- `/=`a /= 5 等价于 a = a / 5
- `%=`a %= 5 等价于 a = a % 5
## 比较运算符
比较运算符可以比较两个值之间的大小关系如果关系成立它会返回true如果关系不成立则返回false
比较运算符有很多种比如
```
> 大于号
< 小于号
>= 大于或等于
<= 小于或等于
== 等于
=== 全等于
!= 不等于
!== 不全等于
```
**比较运算符得到的结果都是布尔值要么是true要么是false**
举例如下
```javascript
var result = 5 > 10; // false
```
### 非数值的比较
1对于非数值进行比较时会将其转换为数字然后再比较
举例如下
```javascript
console.log(1 > true); //false
console.log(1 >= true); //true
console.log(1 > "0"); //true
//console.log(10 > null); //true
//任何值和NaN做任何比较都是false
console.log(10 <= "hello"); //false
console.log(true > false); //true
```
2特殊情况如果符号两侧的值都是字符串时**不会**将其转换为数字进行比较比较两个字符串时比较的是字符串的**Unicode编码**非常重要这里是个大坑很容易踩到
比较字符编码时是一位一位进行比较如果两位一样则比较下一位
比如说当你尝试去比较`"123"``"56"`这两个字符串时你会发现字符串"56"竟然比字符串"123"要大因为 5 1 也就是说下面这样代码的打印结果其实是true:这个我们一定要注意在日常开发中很容易忽视
```javascript
// 比较两个字符串时,比较的是字符串的字符编码,所以可能会得到不可预期的结果
console.log("56" > "123"); // true
```
**因此**当我们在比较两个字符串型的数字时**一定一定要先转型**再比较大小比如 `parseInt()`
3任何值和NaN做任何比较都是false
### `==`符号的强调
注意`==`这个符号它是**判断是否等于**而不是赋值
1`== `这个符号还可以验证字符串是否相同例如
```javascript
console.log("我爱你中国" == "我爱你中国"); // 输出结果为true
```
2`== `这个符号并不严谨会做隐式转换将不同的数据类型**转为相同类型**进行比较大部分情况下都是转换为数字例如
```javascript
console.log("6" == 6); // 打印结果true。这里的字符串"6"会先转换为数字6然后再进行比较
console.log(true == "1"); // 打印结果true
console.log(0 == -0); // 打印结果true
console.log(null == 0); // 打印结果false
```
3undefined 衍生自 null所以这两个值做相等判断时会返回true
```javascript
console.log(undefined == null); //打印结果true。
```
4NaN不和任何值相等包括他本身
```javascript
console.log(NaN == NaN); //false
console.log(NaN === NaN); //false
```
问题那如果我想判断 b的值是否为NaN该怎么办呢
答案可以通过isNaN()函数来判断一个值是否是NaN举例
```javascript
console.log(isNaN(b));
```
如上方代码所示如果 b NaN则返回true否则返回false
### `===`全等符号的强调
**全等在比较时不会做类型转换**如果要保证**绝对等于完全等于**我们就要用三个等号`===`例如
```javascript
console.log("6" === 6); //false
console.log(6 === 6); //true
```
上述内容分析出
- `==`两个等号不严谨"6"和6是true
- `===`三个等号严谨"6"和6是false
另外还有**`==`的反面是`!=``===`的反面是`!==`**例如
```javascript
console.log(3 != 8); //true
console.log(3 != "3"); //false因为3=="3"是true所以反过来就是false。
console.log(3 !== "3"); //true应为3==="3"是false所以反过来是true。
```
## 三元运算符
三元运算符也叫条件运算符
语法
```
条件表达式 ? 语句1 : 语句2;
```
**执行的流程**
条件运算符在执行时首先对条件表达式进行求值
- 如果该值为true则执行语句1并返回执行结果
- 如果该值为false则执行语句2并返回执行结果
如果条件的表达式的求值结果是一个非布尔值会将其转换为布尔值然后再运算
## 运算符的优先级
运算符的优先级如下优先级从高到低
- `.``[]``new`
- `()`
- `++``--`
- `!``~``+`单目`-`单目`typeof``void``delete`
- `%``*``/`
- `+`双目`-`双目
- `<<``>>``>>>`
- 关系运算符`<``<=``>``>=`
- `==``!==``===``!==`
- `&`
- `^`
- `|`
- `&&`
- `||`
- `?:`
- `=``+=``-=``*=``/=``%=``<<=``>>=``>>>=``&=``^=``|=`
- `,`
注意逻辑与 `&&` 比逻辑或 `||` 的优先级更高
备注你在实际写代码的时候如果不清楚哪个优先级更高可以把括号运用上
## Unicode 编码
> 这一段中我们来讲引申的内容Unicode编码的使用
各位同学可以先在网上查一下Unicode 编码表
1在字符串中可以使用转义字符输入Unicode编码格式如下
```
\u四位编码
```
举例如下
```javascript
console.log("\u2600"); // 这里的 2600 采用的是16进制
console.log("\u2602"); // 这里的 2602 采用的是16进制。
```
打印结果
![](http://img.smyhvae.com/20181222_1218.png)
2我们还可以在 HTML 网页中使用Unicode编码格式如下
```
&#四位编码;
```
PS我们知道Unicode编码采用的是16进制但是这里的编码需要使用10进制
举例如下
```html
<h1 style="font-size: 100px;">&#9860;</h1>
```
打印结果
![](http://img.smyhvae.com/20181222_1226.png)
## 我的公众号
想学习**代码之外的技能**不妨关注我的微信公众号**千古壹号**
扫一扫你将发现另一个全新的世界而这将是一场美丽的意外
![](http://img.smyhvae.com/20200101.png)