Web/03-JavaScript基础/04-运算符.md
qianguyihao 0b021571dd update
2019-07-28 20:39:09 +08:00

622 lines
15 KiB
Markdown
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.

> 本文首发于[博客园](https://www.cnblogs.com/smyhvae/p/8306146.html),并在[GitHub](https://github.com/qianguyihao/Web)上持续更新**前端的系列文章**。欢迎在GitHub上关注我一起入门和进阶前端。
我们在本文件夹的[第二篇](https://github.com/smyhvae/Web/blob/master/03-JavaScript%E5%9F%BA%E7%A1%80/02-%E5%8F%98%E9%87%8F.md)里讲到了JS中**变量**的概念,本篇文章讲一下**运算符**和表达式。
## 前言
比如说`+`、`*`、`/`、`(` 都是**运算符**,而`3+5/2`则是**表达式**。
### 运算符的定义和分类
运算符也叫操作符。通过运算符可以对一个或多个值进行运算,并获取运算结果。
比如typeof 就是运算符,可以来获得一个值的类型。它会将该值的类型以**字符串**的形式返回number string boolean undefined object。
运算符都是会返回结果的而typeof这个运算符返回的结果就是变量的类型。那返回的结果的类型是什么呢是字符串。
运算符有很多分类,比如:
- 算数运算符
- 自增运算符
- 逻辑运算符
- 赋值运算符
- 关系运算符
- 三元运算符(条件运算符)
## 算数运算符
常见的算数运算符有以下几种:
![](http://img.smyhvae.com/20180117_1651.png)
**求余的举例**
假设用户输入345怎么分别得到3、4、5这三个数呢
**答案**
```
得到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(取余)
```
console.log(3 % 5);
```
输出结果为3。
举例2注意运算符优先级
```
var a = 1 + 2 * 3 % 4 / 3;
```
结果分析:
原式 = 1 + 6 % 4 / 3 = 1 + 2 / 3 = 1.66666666666666
### 算数运算符的注意事项
1当对非Number类型的值进行运算包括`+`、`-`、`*`、`/`会将这些值转换为Number然后再运算。`字符串 + Number`、`字符串 + 字符串`是特例,稍后再讲)
比如:
```javascript
result1 = true + 1; // 2 = 1+ 1
result2 = true + false; // 1 = 1+ 0
result3 = 1 + null; // 1 = 1+ 0
result4 = 100 - '1' // 99
```
2任何值和NaN做运算的结果都是NaN。
3任何的值和字符串做加法运算都会先转换为字符串然后再做拼串操作。
比如:
```javascript
result1 = 1 + 2 + '3' // 33
result2 = '1' + 2 + 3; // 123
```
我们可以利用这一特点来将一个任意的数据类型转换为String我们只需要为任意的数据类型 + 一个 "" 即可将其转换为String。这是一种**隐式**的类型转换由浏览器自动完成实际上它也是调用String()函数。也就是说,`c = c + ""` 等价于 `c = String(c)`
4任何值做`-`、`*`、`/`运算时都会自动转换为Number。
我们可以利用这一特点,为一个值`-0`、`*1`、`/1`来将其转换为Number。原理和Number()函数一样,使用起来更加简单。
### 乘方
如果想计算 `a 的 b 次方`,可以使用如下函数:
```
Math.pow(a, b);
```
Math的中文是“数学”pow是“power 幂”。
**举例1**
![](http://img.smyhvae.com/20180117_1730.png)
代码实现:
```
var a = Math.pow(3, Math.pow(2, 2));
console.log(a);
```
**举例2**
![](http://img.smyhvae.com/20180117_1740.png)
代码实现:
```
var a = Math.pow(Math.pow(3, 2), 4);
console.log(a);
```
### 开方
如果想计算数值a的开二次方可以使用如下函数
```
Math.sqrt(a);
```
sqrt即“square 开方”。比如:
```
var a = Math.sqrt(36);
```
## 一元运算符
一元运算符,只需要一个操作数。
常见的一元运算符如下。
### 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);
```
打印结果:
![](http://img.smyhvae.com/20181221_2050.png)
### 负号 `-`
负号可以对数字进行取反。
## 自增和自减
### 自增 `++`
自增分成两种:`a++`和`++a`。
1对于一个变量自增以后原变量的值会**立即**自增1。也就是说无论是 `a++` 还是`++a`都会立即使原变量的值自增1。
2**我们要注意的是**`a`是变量,而`a++`和`++a`是**表达式**。
那这两种自增,有啥区别呢?区别是:`a++` 和 `++a`的值不同:(也就是说,表达式的值不同)
- `a++`的值等于原变量的值a自增前的值
- `++a`的值等于新值 a自增后的值
### 自减 `-- `
原理同上。
### 代码举例
```javascript
var n1=10;
var n2=20;
var n = n1++; //n1 = 11 n1++ = 10
console.log('n='+n); // 10
console.log('n1='+n1); //11
n = ++n1 //n1 = 12 ++n1 =12
console.log('n='+n); //12
console.log('n1='+n1); //12
n = n2--;// n2=19 n2--=20
console.log('n='+n); //20
console.log('n2='+n2); //19
n = --n2; //n2=18 --n2 = 18
console.log('n='+n); //18
console.log('n2='+n2); //18
```
## 逻辑运算符
逻辑运算符有三个:
- `&&` 与(且):两个都为真,结果才为真。
- `||` 或:只要有一个是真,结果就是真。
- `!` 非:对一个布尔值进行取反。
**连比的写法:**
来看看逻辑运算符连比的写法。
举例1
```javascript
console.log(3 < 2 && 2 < 4);
```
输出结果为false。
举例2判断一个人的年龄是否在18~60岁之间
```javascript
var a = prompt("请输入您的年龄");
alert(a>=18 && a<= 65);
```
PS上面的这个`a>=18 && a<= 65`千万别想当然的写成` 18<= a <= 65`,没有这种语法。
### 注意事项
1能参与逻辑运算的都是布尔值。
2JS中的`&&`属于**短路**的与如果第一个值为false则不会看第二个值。举例
```javascript
//第一个值为true会检查第二个值
true && alert("看我出不出来!!"); // 可以弹出 alert 框
//第一个值为false不会检查第二个值
false && alert("看我出不出来!!"); // 不会弹出 alert 框
```
3JS中的`||`属于**短路**的或如果第一个值为true则不会看第二个值。举例
4如果对**非布尔值**进行逻辑运算,则会**先将其转换为布尔值**,然后再操作。举例:
```javascript
var a = 10;
a = !a;
console.log(a); // false
console.log(typeof a); // boolean
```
上面的例子,我们可以看到,对非布尔值进行`!`操作之后,返回结果为布尔值。
### 非布尔值的与或运算【重要】
> 之所以重要,是因为在实际开发中,我们经常用这种代码做容错处理。
非布尔值进行**与或运算**时,会先将其转换为布尔值,然后再运算,但返回结果是**原值**。比如说:
```javascript
var result = 5 && 6; // 运算过程true && true;
console.log('result' + result); // 打印结果6也就是说最后面的那个值。
```
上方代码可以看到,虽然运算过程为布尔值的运算,但返回结果是原值。
那么,返回结果是哪个原值呢?我们来看一下。
**与运算**的返回结果:(以两个非布尔值的运算为例)
- 如果第一个值为true则必然返回第二个值所以说如果所有的值都为true则返回的是最后一个值
- 如果第一个值为false则直接返回第一个值
**或运算**的返回结果:(以两个非布尔值的运算为例)
- 如果第一个值为true则直接返回第一个值
- 如果第一个值为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` 作为**兜底**图片。这种写法,在实际开发中经常用到。
## 赋值运算符
可以将符号右侧的值赋值给符号左侧的变量。
举例:
- `+=`。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编码**。【非常重要,这里是个大坑】
比较字符编码时,是一位一位进行比较。如果两位一样,则比较下一位,所以借用它可以来对英文进行排序。
PS所以说当你尝试去比较`"123"`和`"56"`这两个字符串时,你会发现,字符串"56"竟然比字符串"123"要大。也就是说下面这样代码的打印结果其实是true:(这个我们一定要注意,在日常开发中,很容易忽视)
```javascript
// 比较两个字符串时,比较的是字符串的字符编码,所以可能会得到不可预期的结果
console.log("56" > "123"); // true
```
**因此**:当我们在比较两个字符串型的数字时,**一定一定要先转型**,比如 `parseInt()`
3任何值和NaN做任何比较都是false。
### `==`符号的强调
注意`==`这个符号,它是**判断是否等于**,而不是赋值。
1`== `这个符号,还可以验证字符串是否相同。例如:
```
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
```
问题:那如果我想判断 b的值是否为NaN该怎么办呢
答案可以通过isNaN()函数来判断一个值是否是NaN。举例
```javascript
console.log(isNaN(b)); //false
```
如上方代码所示,如果 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编码的使用。
1、在字符串中可以使用转义字符输入Unicode编码。格式如下
```
\u四位编码
```
举例如下:
```javascript
console.log("\u2600"); // 这里的 2600 采用的是16进制
console.log("\u2602"); // 这里的 2602 采用的是16进制。
```
打印结果:
![](http://img.smyhvae.com/20181222_1218.png)
2、同样我们可以在网页中使用Unicode编码。格式如下
```
&#编码;
```
PS我们知道Unicode编码采用的是16进制但是这里的编码需要使用10进制。
举例如下:
```html
<h1 style="font-size: 100px;">&#9860;</h1>
```
打印结果:
![](http://img.smyhvae.com/20181222_1226.png)
## 我的公众号
想学习<font color=#0000ff>**代码之外的技能**</font>?不妨关注我的微信公众号:**千古壹号**id`qianguyihao`)。
扫一扫,你将发现另一个全新的世界,而这将是一场美丽的意外:
![](http://img.smyhvae.com/2016040102.jpg)