![JS全书:JavaScript Web前端开发指南](https://wfqqreader-1252317822.image.myqcloud.com/cover/366/32858366/b_32858366.jpg)
3.5 运算符
3.5.1 算术运算符
1. 加法(+)、减法(-)、乘法(*)、除法(/)
- 加法(+)运算符对操作数进行求和,也可用来连接两个字符串。
- 减法(-)运算符对操作数进行求差。
- 乘法(*)运算符对操作数进行求积。
- 加法(+)运算符对操作数进行求商。
语法:
js expr1 + expr2; expr1 - expr2; expr1 * expr2; expr1 / expr2;
示例代码:
![](https://epubservercos.yuewen.com/A25E65/17640316907888206/epubprivate/OEBPS/Images/Figure-P64_45530.jpg?sign=1738987433-f6c60t6CMGw9iTnSebQgiXNBDzAzKLBc-0-7a2bd253cef79b4a9e4e21799ea291d5)
当加法(+)运算符用来连接字符串时,JavaScript会将操作数进行隐式类型转换后,再进行连接,示例如下。
![](https://epubservercos.yuewen.com/A25E65/17640316907888206/epubprivate/OEBPS/Images/Figure-P64_45532.jpg?sign=1738987433-IJywRXra292HXP3tXoZqtz3evRaZyUrJ-0-91481907ac569f7f9ab77cf847fbbc19)
2. 幂(**)
对被操作数进行乘方运算。
语法:js expr1 ** expr2; expr1为底数,expr2为指数。
示例代码:
![](https://epubservercos.yuewen.com/A25E65/17640316907888206/epubprivate/OEBPS/Images/Figure-P64_45534.jpg?sign=1738987433-NooXfs2hjAkA58RNYZBMrxwiJXWkO2IF-0-e9a836536e9117ad0c4013979fb824a4)
3. 取模(%)
返回第一个操作数除以第二个操作数的余数。
语法:
expr1 % expr2;
示例代码:
![](https://epubservercos.yuewen.com/A25E65/17640316907888206/epubprivate/OEBPS/Images/Figure-P65_45538.jpg?sign=1738987433-WLuQIXyyqc2Z7fg6ZQnnwFGoLMogOUHP-0-2fad5d883e6f4e3b36b3100d3d5aeb3e)
4. 一元正(+)
对操作数进行取值操作并返回,如果操作数不是Number类型,会将其转化为Number类型,示例如下。
![](https://epubservercos.yuewen.com/A25E65/17640316907888206/epubprivate/OEBPS/Images/Figure-P65_45540.jpg?sign=1738987433-5dOWG8Ka8vF8rSfjSntCQyZyVDqhUip9-0-30bb14070b9ee1c1f012f8c075f426ac)
5. 一元反(-)
用来对操作数进行取反操作,示例如下。
![](https://epubservercos.yuewen.com/A25E65/17640316907888206/epubprivate/OEBPS/Images/Figure-P65_45542.jpg?sign=1738987433-rtLqJlBCRL4lE85v5T3aT9xzT22Y7C2q-0-89ee44aefbe433c3db4e2f9ce2c3212c)
6. 递增(++)、递减(--)
递增(++)运算符将操作数+1后返回一个数值,递减(--)运算符将操作数-1后返回一个数值。
语法:
expr++; ++expr;
expr--; --expr;
示例代码:
```js let foo = 1, let baz = 1;
// 先取值再计算 foo++; // -> 1 baz--; // -> 1
console.log(foo,baz); // > 2,0 ```
上述代码中,定义了两个变量foo和baz,并赋值为1,之后分别对foo和baz进行递增和递减操作,此时返回值均为1,这是因为递增和递减运算符两种使用方式的返回值不同,具体如下。
- 位于被操作数之后,返回递增(减)前的数值。
- 位于被操作数之前,返回递增(减)后的数值。
示例代码:
![](https://epubservercos.yuewen.com/A25E65/17640316907888206/epubprivate/OEBPS/Images/Figure-P66_45550.jpg?sign=1738987433-0bjEljEsrhEsuhuXV2lC2uXwGP4NHdPe-0-5ef3a4278a4748e1eb9f0125195506be)
3.5.2 逻辑运算符
1. 逻辑与(&&)
逻辑与(&&)会在遇到能够被转化为false的操作数后返回该操作数,如果没有,则返回最后一个操作数。
语法:
expr1 && expr2;
示例代码:
![](https://epubservercos.yuewen.com/A25E65/17640316907888206/epubprivate/OEBPS/Images/Figure-P66_28053.jpg?sign=1738987433-62e5fLuXk5F3nvGezO7oTtEDvXV7YFIR-0-9c8811d99806ba024c23cebf6fae9ce5)
2. 逻辑或(||)
逻辑或(||)会在遇到能够被转化为true的操作数后返回该操作数,如果没有,则返回最后一个操作数。
语法:
js expr1 || expr2;
示例代码:
![](https://epubservercos.yuewen.com/A25E65/17640316907888206/epubprivate/OEBPS/Images/Figure-P66_45553.jpg?sign=1738987433-kay4nG8dim8nqFurHwRLieJYc6jhuPxS-0-00ec8df73a0a86d04bc642c005b1a78c)
利用逻辑与(&&)和逻辑或(||)的这个特性,可以方便地做短路运算,以精简代码,示例如下。
function foo(name){ return name || ''; }
3. 逻辑非(!)
如果操作数能够被转化为true,则逻辑非(!)返回false;如果操作数能够被转化为false,则逻辑非(!)返回true。
语法:
1expr;
示例代码:
![](https://epubservercos.yuewen.com/A25E65/17640316907888206/epubprivate/OEBPS/Images/Figure-P67_45557.jpg?sign=1738987433-kzvOz8YyHxRFYSQ68ohj1bWSglblKcHN-0-46813ae7837f0492d2eccce6dae5d6c3)
有时,你可能会看到!!的用法,!!相当于使用Boolean进行类型转换,但在if语句中,!!是不必要的,因为if语句本身会对其中的表达式进行Boolean操作,使用!!反而会增加额外的性能消耗,示例如下。
if(expr){ // 相当于 Boolean(expr)
}
// 不推荐的方式 if(!!expr){ // 相当于 Boolean(Boolean(expr))
}
3.5.3 比较运算符
比较运算符返回一个布尔值,表示两个操作数的比较结果。
1. 大于(>)、小于(<)、大于或等于(>=)、小于或等于(< =)
比较运算符在比较expr1和expr2时,如果expr1和expr2类型不同,则将它们转化成字符串、数字或布尔值进行比较,具体如下。
- 大于(>):expr1大于expr2时,返回true。
- 小于(<):expr1小于expr2时,返回true。
- 大于或等于(>=):expr1大于或等于expr2时,返回true。
- 小于或等于(<=):expr1小于或等于expr2时,返回true。
语法:
expr1 > expr2; expr1 < expr2; expr1 >= expr2; expr1 <= expr2;
示例代码:
![](https://epubservercos.yuewen.com/A25E65/17640316907888206/epubprivate/OEBPS/Images/Figure-P68_45561.jpg?sign=1738987433-S3m5BOpcnRzbN24xfatKwbMMBFCze3XE-0-67721b84c5b3ea25cd5c1c7c3d33c38b)
2. 相等(==)、不相等(!=)
相等(==)和不相等(!=)会将两个操作数转换类型后进行比较。
语法:
js expr1 == expr2; expr1 != expr2;
示例代码:
![](https://epubservercos.yuewen.com/A25E65/17640316907888206/epubprivate/OEBPS/Images/Figure-P68_45565.jpg?sign=1738987433-8n32zBIcpqDx0ydVCDbnrmSSWs5EUrEJ-0-df393cafdbd270e0a51353ad60ca7670)
3. 严格相等(===)、严格不等(!==)
严格相等(===)和严格不等(!==)直接比较两个操作数,不进行类型转换。
语法:
expr1 === expr2; expr1 !== expr2;
示例代码:
![](https://epubservercos.yuewen.com/A25E65/17640316907888206/epubprivate/OEBPS/Images/Figure-P68_45569.jpg?sign=1738987433-sXtFtpIGOxDPPh5BLV9zkGlsUwgAfVbl-0-6b7b21e3d1a63adf2f1dc2434e26114d)
3.5.4 三元运算符
三元运算符对第一个表达式进行判断,并根据其结果返回不同的表达式。
语法:
js expr ? expr1 : expr2;
如果expr转化为布尔值后为true,则返回expr1,否则返回expr2。
示例代码:
js true ? 1 : 2; // -> 1 false ? 1 : 2; // -> 2
3.5.5 赋值
赋值运算符将表达式右边的值赋值给左边的变量。
1. 赋值运算符
语法:
expr1 = expr2;
示例代码:
let a = 1; console.log(a); // > 1 let b = a; console.log(b); // > 1
2. 复合赋值
复合赋值是将某些运算符与赋值运算符组合使用,示例如下。
![](https://epubservercos.yuewen.com/A25E65/17640316907888206/epubprivate/OEBPS/Images/Figure-P69_45581.jpg?sign=1738987433-aTxBm8Z1x1LHSFCLEkGSyiPbx0ZtmDCS-0-e45e4d06d8747c34630ee6e40e04b650)
3. 解构赋值
解构赋值用于从数组或对象提取值,并保存到新的变量中。
数组的解构赋值,示例如下。
![](https://epubservercos.yuewen.com/A25E65/17640316907888206/epubprivate/OEBPS/Images/Figure-P69_45583.jpg?sign=1738987433-QeUeNyvr3LGcq4vhVaN6949WA3twvaNG-0-70e8bc4dd20eaebe19fbcb0d88fc3e4d)
对象的解构赋值,示例如下。
![](https://epubservercos.yuewen.com/A25E65/17640316907888206/epubprivate/OEBPS/Images/Figure-P70_45586.jpg?sign=1738987433-8kfkncDq9KvwVSPLAVKCjKGe7nH4XlVS-0-4e00ded45a019c5359c4b8d391b414fd)
字符串的解构赋值,示例如下。
![](https://epubservercos.yuewen.com/A25E65/17640316907888206/epubprivate/OEBPS/Images/Figure-P70_45589.jpg?sign=1738987433-c64VIpy8EbEFhAIUNBoxxCKevU9zfDUZ-0-57d63deb059900b80213b0513e2206d6)
3.5.6 位运算符
按位操作符(Bitwise operators)将其操作数(operands)当作32位的比特序列(由0和1组成),而不是十进制、十六进制或八进制数值。
例如,十进制数9,用二进制表示则为1001。按位操作符操作数字的二进制形式,但是返回值依然是标准的JavaScript数值。
表3-4总结了JavaScript中的按位操作符。
表3-4 位运算符
![](https://epubservercos.yuewen.com/A25E65/17640316907888206/epubprivate/OEBPS/Images/Figure-T70_45590.jpg?sign=1738987433-NU2qllGrpnrtVDYrwpC4HcbrWAWblQ6n-0-2000563d8d8a2c6777d6610864521a32)
示例代码:
![](https://epubservercos.yuewen.com/A25E65/17640316907888206/epubprivate/OEBPS/Images/Figure-P71_45591.jpg?sign=1738987433-1Ym5Ht6fVNSHWMXjKeWbqxgwlDsrdyP8-0-1037a5fe451c48218c2c109cbbcbcac1)
位运算符也可与算术运算符组合使用。
3.5.7 异步操作符async function
在介绍async function前,我们先来讲解ES6中出现的Promise,Promise是一个构造函数,其提供了异步编程的解决方案,以解决回调函数的问题,同时,其提供的all方法也为异步并发(例如并发请求)提供了处理机制。
Promise的用法如下。
![](https://epubservercos.yuewen.com/A25E65/17640316907888206/epubprivate/OEBPS/Images/Figure-P71_45593.jpg?sign=1738987433-EJrFdaogGwkTsJETKwlG2mnYrdLfuvvu-0-5e735071f850efe9bcb7ff79c165179e)
ES8中引入了async function,用来简化异步操作,示例如下。
![](https://epubservercos.yuewen.com/A25E65/17640316907888206/epubprivate/OEBPS/Images/Figure-P72_45595.jpg?sign=1738987433-PBD0FdET3ugAKgA0jcfYN2COlqN73yY6-0-51ca030e89da47aa4316708d1ff580cb)
如果async function内部有await命令,则需要等所有的await后面的Promise对象执行完,才会返回,示例如下。
![](https://epubservercos.yuewen.com/A25E65/17640316907888206/epubprivate/OEBPS/Images/Figure-P72_45597.jpg?sign=1738987433-RJfxtWtNTPfkkTbKTTNNzsUoIqfpY60i-0-b47d4aaba4aff0b729cb50d754c7835c)
上述代码中的then方法也可以使用await来省略,await会在等待Promise对象执行完后,直接获取resolve的值,示例如下。
await只能在async function定义的函数中使用,下面的示例创建了一个立即调用的函数表达式,关于立即调用函数表达式请参阅函数一章。
![](https://epubservercos.yuewen.com/A25E65/17640316907888206/epubprivate/OEBPS/Images/Figure-P73_45600.jpg?sign=1738987433-QRRzKKWQ2smIzfnmwgqEzGFDdi6dCclt-0-07c1718d888168008aae9c69921ea24d)
上面的示例中,最终执行的结果与直接调用then方法的结果有些不同,then方法的示例会在第1秒后输出2,第2秒后输出2,而await的示例会在第1秒后输出2,之后才执行第二个await,间隔2秒后输出2,因此,实际上是第3秒输出的2,这是await的特点,也是async function/await致力于解决的痛点之一,将异步代码同步化,降低异步编程的负担。当然,如果你想让上面的示例与调用then方法的结果相同,将其拆分成2个async function即可。
在await中,去掉了then方法那样的链式操作,因此,也不能使用catch方法,如果要捕获其中的错误,可以使用try…catch语句,示例如下。
![](https://epubservercos.yuewen.com/A25E65/17640316907888206/epubprivate/OEBPS/Images/Figure-P73_45602.jpg?sign=1738987433-45viMf2dSv2FnUeqj2iJM4ZzZOOMmtgu-0-8a1ccb6e9eeea15e2b80a178ec55f905)
此外,ES6也提供了Generator函数来处理异步编程,有了async function则不推荐再使用function*来处理异步问题。
Generator函数由function*声明,在函数内部,不仅可以使用return返回,还可以使用yield返回,和await类似,yield只能在function*声明的函数内部使用,示例如下。
![](https://epubservercos.yuewen.com/A25E65/17640316907888206/epubprivate/OEBPS/Images/Figure-P73_45604.jpg?sign=1738987433-hbWNcs8D9QM4dDQ82uEWw0vCylHdwN6E-0-46500cb4c8d6dd62e442b31a64f2186b)
Generator函数是可以嵌套的,示例如下。
![](https://epubservercos.yuewen.com/A25E65/17640316907888206/epubprivate/OEBPS/Images/Figure-P73_45606.jpg?sign=1738987433-Ntw2LXwGV1wuPwZJ3U5Tkgwjem5TvQ4H-0-9028c375b43f3ed93210cfa05413cc11)
现在,使用Generator函数运行上面的两个示例。
![](https://epubservercos.yuewen.com/A25E65/17640316907888206/epubprivate/OEBPS/Images/Figure-P74_45609.jpg?sign=1738987433-p01cj1up6f3bkgb7wDrds2eyxMy4SeQ2-0-a2a4b7a10dc91eb629ff7b16f788f985)
相比于async function,function*的代码更加烦琐,毕竟Generator函数不是为异步而生的,Generator函数更适用于遍历器(Iterator,参照本书相应章节)生成、状态管理、无限序列等场景。
3.5.8 其他运算符
1. delete
从对象中删除一个属性,或从数组中移除一个元素,示例如下。
![](https://epubservercos.yuewen.com/A25E65/17640316907888206/epubprivate/OEBPS/Images/Figure-P75_29266.jpg?sign=1738987433-kstmypmqEAj6YoijfBljmjoSvTaIOMy9-0-1b0898fbfc91196014187e4438bf5d54)
2. typeof与instanceof
可查看3.3.4小节。
3. void
void操作符对其后的表达式求值并返回undefined,一般用来替代undefined,示例如下。
![](https://epubservercos.yuewen.com/A25E65/17640316907888206/epubprivate/OEBPS/Images/Figure-P75_45612.jpg?sign=1738987433-BCFzXgE3O1WvHSmSUoPb7l3PXDgOKqVR-0-cc1c8b95d50edf995912fe3bbccf7ad7)
4. new
new运算符通过一个构造函数创建一个实例,并返回这个实例。
其语法如下。
new constructor[([arguments])]
其中,constructor是一个内置或自定义的构造函数,arguments为可选的入参,在constructor中被使用。
内置的构造函数有很多,例如,Number、String、Boolean、Date、Object、Function等,示例如下。
![](https://epubservercos.yuewen.com/A25E65/17640316907888206/epubprivate/OEBPS/Images/Figure-P76_45616.jpg?sign=1738987433-d8JF2NesU9kWzr7UrrAj4SGfjHClw2kr-0-a02275466bb089acff763b581ca5c635)
创建一个自定义的构造函数,示例如下。
function People {};
// 通过 new 运算符创建一个实例 let p = new People();
5. in
返回一个布尔值,表示对象中是否包含该属性,示例如下。
![](https://epubservercos.yuewen.com/A25E65/17640316907888206/epubprivate/OEBPS/Images/Figure-P76_45620.jpg?sign=1738987433-uMuYNiZZT3eSEoaGb4dmAMeds45HhVuJ-0-71286fb27c59df6a7aab32c75cab91fc)
6. 逗号
逗号运算符顺序执行表达式,并返回最后一个表达式,示例如下。
1, 2, 3; // -> 3
7. 括号()
用来提升运算优先级。
3.5.9 运算符优先级
运算符优先级规定了表达式执行运算时的顺序——按照运算符的优先级从高到低执行。如下:先乘除后加减,表3-5列出了JavaScript中的运算符优先级。
表3-5 运算符优先级
![](https://epubservercos.yuewen.com/A25E65/17640316907888206/epubprivate/OEBPS/Images/Figure-T76_45623.jpg?sign=1738987433-gYuZPpRwYISPfzh7xIKOptxqn3RiZiP5-0-6d31397074a4101fda590ccbb82cfbfb)
续表
![](https://epubservercos.yuewen.com/A25E65/17640316907888206/epubprivate/OEBPS/Images/Figure-T78_45625.jpg?sign=1738987433-JLbptbpyCMpzxdS99bhX5hC1mvgTfs3Y-0-3a7e8231f35cc5dae8e7b3abf33d224e)
练习
- 使用算术运算符。
- 使用逻辑运算符。
- 使用解构运算符。
- 使用new运算符创建一个对象。