这些JS中强大的操作符,总有几个你没

1.数值分割符_

2.逗号运算符,

3.零合并操作符??

4.可选链操作符?.

5.私有方法/属性

6.位运算符与

7.位运算符与

8.双位运算符~~

9.短路运算符与

10.void运算符

11.其他常用操作符

12.操作符优先级

JS里的操作符大家每天都在使用,还有一些ES、ES新加的实用操作符,这些共同构成了JS灵活的语法生态。

本文除介绍常用的操作符之外,还会介绍JS里一些不常用但是很强大的操作符,下面我们一起来看看吧~

1.数值分割符_

ES引入了数值分割符_,在数值组之间提供分隔,使一个长数值读起来更容易。Chrome已经提供了对数值分割符的支持,可以在浏览器里试起来。

letnumber=___//0太多了不用数值分割符眼睛看花了console.log(number)//输出

此外,十进制的小数部分也可以使用数值分割符,二进制、十六进制里也可以使用数值分割符。

0x11_1===0x//true十六进制0.11_1===0.//true十进制的小数0b11_1===0b//true二进制2.逗号运算符,

什么,逗号也可以是运算符吗?是的,曾经看到这样一个简单的函数,将数组的第一项和第二项调换,并返回两项之和:

functionreverse(arr){return[arr[0],arr[1]]=[arr[1],arr[0]],arr[0]+arr[1]}constlist=[1,2]reverse(list)//返回3,此时list为[2,1]

逗号操作符对它的每个操作数求值(从左到右),并返回最后一个操作数的值。

expr1,expr2,expr3...

会返回最后一个表达式expr3的结果,其他的表达式只会进行求值。

3.零合并操作符??

零合并操作符??是一个逻辑操作符,当左侧的操作数为null或者undefined时,返回右侧操作数,否则返回左侧操作数。

expr1??expr2

空值合并操作符一般用来为常量提供默认值,保证常量不为null或者undefined,以前一般使用

来做这件事variable=variable

bar。然而,由于

是一个布尔逻辑运算符,左侧的操作数会被强制转换成布尔值用于求值。任何假值(0,,NaN,null,undefined)都不会被返回。这导致如果你使用0、、NaN作为有效值,就会出现不可预料的后果。

正因为

存在这样的问题,而??的出现就是解决了这些问题,??只会在左侧为undefined、null时才返回后者,??可以理解为是

的完善解决方案。

可以在浏览器中执行下面的代码感受一下:

undefined

default//defaultnull

default//defaultfalse

default//default0

default//defaultundefined??default//defaultnull??default//defaultfalse??default//false0??default//0

另外在赋值的时候,可以运用赋值运算符的简写??=

leta={b:null,c:10}a.b??=20a.c??=20console.log(a)//输出{b:20,c:10}4.可选链操作符?.

可选链操作符?.允许读取位于连接对象链深处的属性的值,而不必验证链中的每个引用是否有效。?.操作符的功能类似于.链式操作符,不同之处在于,在引用为null或者undefined的情况下不会引起错误,该表达式短路返回值是undefined。

当尝试访问可能不存在的对象属性时,可选链操作符将会使表达式更短、更简明。

constobj={a:foo,b:{c:bar}}console.log(obj.b?.c)//输出barconsole.log(obj.d?.c)//输出undefinedconsole.log(obj.func?.())//不报错,输出undefined

以前可能会通过objobj.aobj.a.b来获取一个深度嵌套的子属性,现在可以直接obj?.a?.b即可。

可选链除了可以用在获取对象的属性,还可以用在数组的索引arr?.[index],也可以用在函数的判断func?.(args),当尝试调用一个可能不存在的方法时也可以使用可选链。

调用一个对象上可能不存在的方法时(版本原因或者当前用户的设备不支持该功能的场景下),使用可选链可以使得表达式在函数不存在时返回undefined而不是直接抛异常。

constresult=someInterface.customFunc?.()5.私有方法/属性

在一个类里面可以给属性前面增加#私有标记的方式来标记为私有,除了属性可以被标记为私有外,getter/setter也可以标记为私有,方法也可以标为私有。

classPerson{getDesc(){returnthis.#name++this.#getAge()}#getAge(){returnthis.#age}//私有方法get#name(){returnfoo}//私有访问器#age=23//私有属性}consta=newPerson()console.log(a.age)//undefined直接访问不到console.log(a.getDesc())//foo.位运算符与

有符号右移操作符将第一个操作数向右移动指定的位数,多余的位移到右边被丢弃,高位补其符号位,正数补0,负数则补1。因为新的最左位与前一个最左位的值相同,所以符号位(最左位)不会改变。

(0b1).toString(2)//"11"(-0b1).toString(2)//"-"感觉跟直觉不一样

正数的好理解,负数怎么理解呢,负数在计算机中存储是按照补码来存储的,补码的计算方式是取反加一,移位时将补码形式右移,最左边补符号位,移完之后再次取反加一求补码获得处理后的原码。

-//真值00//原码(高位的0无所谓,后面加不到)11//补码11//算数右移00//移位后求补码获得原码-//移位后的真值

一般我们用来将一个数除2,相当于先舍弃小数位然后进行一次Math.floor:

////6相当于13.91//6-//-7相当于-13.91//-7

无符号右移操作符,将符号位作为二进制数据的一部分向右移动,高位始终补0,对于正整数和算数右移没有区别,对于负数来说由于符号位被补0,成为正数后就不用再求补码了,所以结果总是非负的。即便右移0个比特,结果也是非负的。

(0b1).toString(2)//"11"(-0b1).toString(2)//"1"

可以这样去理解

-//真值0//原码1//补码0//算数右移(由于右移后成为正数,就不要再求补码了)//移位后的真值

左移运算符与之类似,左移很简单左边移除最高位,低位补0:

(0b11).toString(2)//"-0"(0b11).toString(2)//"-0"

PS:JS里面没有无符号左移,而且其他语言比如JAVA也没有无符号左移。

7.位运算符与

位运算符是按位进行运算,与、

或、~非、^按位异或:

:0

:0~:0^:0----------------0011

使用位运算符时会抛弃小数位,我们可以利用这个特性来给数字取整,比如给任意数字上二进制的32个1,或者

上0,显而易见后者简单些。

所以我们可以对一个数字

0来取整,负数也同样适用

1.3

0//1-1.9

0//-1

判断奇偶数除了常见的取余%2之外,也可以使用1,来判断二进制数的最低位是不是1,这样除了最低位之外都被置0,取余的结果只剩最低位,是不是很巧妙。负数也同样适用:

constnum=3!!(num1)//true!!(num%2)//true8.双位运算符~~

可以使用双位操作符来替代正数的Math.floor(),替代负数的Math.ceil()。双否定位操作符的优势在于它执行相同的操作运行速度更快。

Math.floor(4.9)===4//true//简写为:~~4.9===4//true

不过要注意,对正数来说~~运算结果与Math.floor()运算结果相同,而对于负数来说与Math.ceil()的运算结果相同:

~~4.5//4Math.floor(4.5)//4Math.ceil(4.5)//5~~-4.5//-4Math.floor(-4.5)//-5Math.ceil(-4.5)//-4

PS:注意~~(num/2)方式和num1在值为负数时的差别

9.短路运算符与

我们知道逻辑与与逻辑或

是短路运算符,短路运算符就是从左到右的运算中前者满足要求,就不再执行后者了。

可以理解为:

为取假运算,从左到右依次判断,如果遇到一个假值,就返回假值,以后不再执行,否则返回最后一个真值

为取真运算,从左到右依次判断,如果遇到一个真值,就返回真值,以后不再执行,否则返回最后一个假值

letparam1=expr1expr2letparam2=expr1

expr2短路运算符

因此可以用来做很多有意思的事,比如给变量赋初值:

letvariable1letvariable2=variable1

foo

如果variable1是真值就直接返回了,后面短路就不会被返回了,如果为假值,则会返回后面的foo。

也可以用来进行简单的判断,取代冗长的if语句:

letvariable=paramparam.prop//有了可选链之后可以直接param?.prop

如果param如果为真值则返回param.prop属性,否则返回param这个假值,这样在某些地方防止param为undefined的时候还取其属性造成报错。

10.void运算符

void运算符对给定的表达式进行求值,然后返回undefined

可以用来给在使用立即调用的函数表达式(IIFE)时,可以利用void运算符让JS引擎把一个function关键字识别成函数表达式而不是函数声明。

functioniife(){console.log(foo)}()//报错,因为JS引擎把IIFE识别为了函数声明voidfunctioniife(){console.log(foo)}()//正常调用~functioniife(){console.log(foo)}()//也可以使用一个位操作符(functioniife(){console.log(foo)})()//或者干脆用括号括起来表示为整体的表达式

还可以用在箭头函数中避免传值泄漏,箭头函数,允许在函数体不使用括号来直接返回值。这个特性给用户带来了很多便利,但有时候也带来了不必要的麻烦,如果右侧调用了一个原本没有返回值的函数,其返回值改变后,会导致非预期的副作用。

constfunc=()=voidcustomMethod()//特别是给一个事件或者回调函数传一个函数时

安全起见,当不希望函数返回值是除了空值以外其他值,应该使用void来确保返回undefined,这样,当customMethod返回值发生改变时,也不会影响箭头函数的行为。

11.其他常用操作符三元表达式:很简单了,大家经常用,expr?expr1:expr2如果expr为真值则返回expr1,否则返回expr2赋值运算符简写:加法赋值+=、减法赋值-=、乘法赋值*=、除法赋值/=、求幂赋值**=、按位或复制

=、按位与赋值=、有符号按位右移赋值=、无符号按位右移赋值=、逻辑空赋值??=....求幂运算符:var1**var2相当于Math.pow,结果为var1的var2次方12.操作符优先级

正因为有操作符优先级,所以variable=1,2的含义是将变量先赋值为1,再返回数字2,而不是变量赋值给1,2的返回值2,这是因为=运算符的优先级高于,逗号运算符。再比如表达式6-2*3===01,-*===这四个运算符优先级最高的*先运算,然后-运算符结果为0,===运算符优先级高于而true1的结果为1,所以这就是运算的结果。

下面的表将运算符按照优先级的不同从高(20)到低(1)排列,但这个不是最新的,至少没包括可选链,建议参考这个表[1]或者MDN[2]。

运算符优先级

参考文档:

运算符优先级-JavaScript

MDN[3]JS中可以提升幸福度的小技巧[4]4个未听说过的强大JavaScript操作符聊聊JavaScript中的二进制数[5]

PS:本文收录在在下的博客Github-SHERlocked93/blog[6]系列文章中,欢迎star~

参考资料[1]

运算符优先级-JavaScript

MDN:



转载请注明地址:http://www.gongjingmilanagjml.com/glxf/7623.html
  • 上一篇文章:
  • 下一篇文章: 没有了
  • 热点文章

    • 没有热点文章

    推荐文章

    • 没有推荐文章