JS中的运算符,大家每天都会用到。ES2020和ES2021也新增了一些实用的算子。这些共同构成了JS的灵活性。语法生态学。本文除了介绍常用的运算符外,还将介绍一些JS中不常用但功能强大的运算符。一起来看看吧~1.数值分隔符_ES2021引入了数值分隔符_,在值组中提供字符之间的分隔,让读取长值更容易。Chrome已经提供了对数字分隔符的支持,你可以在浏览器中试用一下。letnumber=100_0000_0000_0000//0用数字分隔符太多了,要看很久console.log(number)//输出100000000000000另外小数部分也可以用数字分隔符,也可以用于二进制和十六进制数字分隔符。0x11_1===0x111//真十六进制0.11_1===0.111//真十进制十进制0b11_1===0b111//真二进制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或未定义时返回右操作数,否则返回左操作数。expr1??expr2空值合并运算符一般用于为常量提供默认值,以确保常量不为空或未定义。过去,||一般是用来做这个的variable=variable||'酒吧'。然而,由于||是布尔逻辑运算符,左侧的操作数被强制转换为布尔值以进行评估。不会返回任何假值(0、''、NaN、null、undefined)。如果您使用0、''、NaN作为有效值,这会导致不可预测的行为。就因为||有这样的问题,并出现??就是为了解决这些问题。??仅当左侧未定义或为空时才返回后者。??可以理解为||的完美解决方案。可以在浏览器中执行如下代码感受一下:undefined||'default'//'default'null||'default'//'default'false||'default'//'default'0||'default'//'default'undefined??'default'//'default'null??'default'//'default'false??'default'//'false'0??'default'//0另外在赋值时可以使用赋值运算符的缩写??=leta={b:null,c:10}a.b??=20a.c??=20console.log(a)//输出{b:20,c:10}4.可选的链接运算符?。可选的链接运算符?。允许读取位于连接对象链深处的属性值,而无需验证链中的每个引用是否有效。?的功能。运算符类似于.链接运算符,除了如果引用为null或未定义它不会导致错误,并且此表达式的短路返回值未定义。当尝试访问可能不存在的对象属性时,可选的链接运算符将使表达式更短、更简洁。constobj={a:'foo',b:{c:'bar'}}console.log(obj.b?.c)//输出barconsole.log(obj.d?.c)//输出undefinedconsole.log(obj.func?.())//没有报错,输出undefined以前可以通过obj&&obj.a&&obj.a.b获取深度嵌套的子属性,现在可以直接obj?.a?.b即可以。可选链除了用于获取对象的属性外,还可以用在数组的索引arr?.[index]中,也可以用在函数的判断func?.(args)中,当尝试调用可能不存在的方法时,也可以使用可选链接。当调用对象上可能不存在的方法时(版本原因或当前用户设备不支持该功能的场景),使用可选链可以使表达式返回undefined,而不是在函数不存在时直接抛出异常.constresult=someInterface.customFunc?.()5.类中的私有方法/属性可以通过在属性前添加#private标记来标记为私有。除了属性可以标记为私有外,getter/setter也可以标记为私有,方法也可以标记为私有。classPerson{getDesc(){returnthis.#name+''+this.#getAge()}#getAge(){returnthis.#age}//私有方法get#name(){return'foo'}//私有访问器#age=23//私有属性}consta=newPerson()console.log(a.age)//undefined不能直接访问console.log(a.getDesc())//foo236.按位运算符>>和>>>有符号右移运算符>>将第一个操作数向右移动指定的位数,并丢弃向右移动的多余部分。高位填充它的符号位,正数填充0,负数填充1。因为新的最左位和之前的最左位的值相同,所以符号位(最左位)不改变。(0b111>>1).toString(2)//"11"(-0b111>>1).toString(2)//"-100"感觉和直觉不一样。正数好理解,负数怎么理解,负数在计算机中的存储是靠补码的。补码的计算方法是取反加一。移位时,补码形式右移,补码最左边的符号。移位完成后反相加补码得到处理后的原码。-111//真值10000111//原码(高0无所谓,后面补不了)11111001//补码11111100//算术右移10000100//移位后求补码得到原码-100//Shift一般我们用>>把一个数除以2,相当于先去掉小数位,再进行一次Math.floor:10>>1//513>>1//6等价于13.9>>1//6-13>>1//-7等价于-13.9>>1//-7无符号右移运算符>>>,符号位右移的一部分二进制数据,高位总是用0填充,对于正整数和算术右移没有区别。对于负数,由于符号位补0,变成正数后不需要补,所以结果总是非负的。即使右移0位,结果也是非负的。(0b111>>>1).toString(2)//"11"(-0b111>>>1).toString(2)//"111111111111111111111111100"可以这样理解-111//真值100000000000000000000000000111//原码111111111111111111111111001//补码0111111111111111111111111100//算术右移(因为右移变成正数所以不求补码)1073741820//左移后的真值移位运算符<<类似,左移很简单,去掉左边的最高位,用0填充低位:(0b11111111111111111100<<1).toString(2)//"-1000"(0b111111111111111111111111111111111111111100<<<1).toString(2)//"-1000》PS:JS里面是没有无符号左移的,其他语言比如JAVA是没有无符号左移的。7.按位运算符&和|bitwiseoperators就是按位运算,&与,|or,~not,^按位异或:&:1010|:1010~:1010^:1010011001100110--------------0010111001011100当使用位运算符时,小数位将被丢弃。我们可以利用这个特性对数字进行四舍五入,比如给任意数加32个二进制1&,或者给任意数加0,显然后者更简单。所以我们可以四舍五入一个数字|0,负数也适用1.3|0//1-1.9|0//-1判断奇偶数除了常见的余数%2,还可以用&1判断a的最低位是否二进制数为1,这样除最低位外全部设为0,余数的结果只是最低位,是不是很巧妙。同样适用于负数:constnum=3!!(num&1)//true!!(num%2)//true8。双位运算符~~可以用双位运算符代替正数的Math.floor(),AlternativetoMath.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)//-4PS:注意~~(num/2)方法和num>>1为负数时的区别9.短路运算符&&和||我们知道逻辑与&&和逻辑或||是短路运算符,短路运算符是从左到右的操作,前者满足要求,后者不再执行。可以理解为:&&是伪操作,从左往右判断。如果遇到假值,则返回一个假值,后面不再执行,否则返回最后一个真值||是真操作,从左到右从右到左判断,遇到真值就返回真值,后面不再执行,否则返回上次的假值letparam1=expr1&&expr2letparam2=expr1||expr2运算符示例说明&&expr1&&expr2如果expr1可以转换为false,则返回expr1,否则返回expr2。因此,当在布尔上下文中使用时,如果两个操作的计算结果都为真,则返回真,否则返回假||expr1||expr2如果expr1可以转换为真,则返回expr1,否则返回expr2。因此,在布尔环境下使用时(if的条件判断中),只要两个运算结果之一为真,则返回真;当两个操作结果都为false时,返回false!!expr如果单个表达式可以转换为真则返回假,否则返回真,所以它可以用来做很多有趣的事情,比如给变量赋初值:letvariable1letvariable2=variable1||'foo'如果variable1为真值则直接返回,后面的短路不会被阻塞返回,如果为假值则返回后面的foo。也可以用来做简单的判断,而不是冗长的if语句:letvariable=param&¶m.prop//有了optionalchain,可以直接param?.prop如果param为真,返回param.prop属性,否则返回param这个是false值,以至于在某些地方,当param未定义时,仍然取其属性导致错误。10.void运算符void运算符对给定的表达式求值并返回undefined,当使用立即调用的函数表达式(IIFE)时,它可以用来给JS引擎一个函数键。该词被识别为函数表达式而不是函数声明。functioniife(){console.log('foo')}()//报错,因为JS引擎将IIFE识别为函数声明voidfunctioniife(){console.log('foo')}()//调用~functioniifenormally(){console.log('foo')}()//也可以使用按位运算符(functioniife(){console.log('foo')})()//或者简单的用括号括起来asIntegral表达式也可以用在箭头函数中,以避免传值泄漏。箭头函数允许直接返回值,而无需在函数体中使用括号。这个功能给用户带来了很多方便,但有时也会带来不必要的麻烦。如果在右侧调用了一个没有返回值的函数,其返回值的改变会造成意想不到的副作用。constfunc=()=>voidcustomMethod()//特别是在将函数传递给事件或回调函数时为了安全,当不希望函数的返回值是null以外的值时,应该使用void来确保返回未定义。这样,当customMethod的返回值改变时,不会影响箭头函数的行为。十一、其他常用运算符1、三元表达式:很简单,大家都经常用,expr?expr1:expr2如果expr为真,则返回expr1,否则返回expr22。速记赋值运算符:加法赋值+=、减法赋值-=、乘法赋值*=、除法赋值/=、求幂赋值**=、按位或复制|=、按位与赋值&=、有符号按位右移赋值>>=,无符号按位右移赋值>>>=,逻辑空赋值??=...3.求幂运算符:var1**var2等价于Math.pow,结果是var1的var2的12次方。运算符优先级是因为有运算符优先级,所以variable=1,2的意思就是给变量赋值一个值1,然后返回数字2,而不是将变量赋值给1,2的返回值2,因为=操作符的优先级很高,对于逗号操作符。又如表达式6-2*3===0&&1,-*===&&优先级最高的四个运算符*先运算,然后-运算结果为0,===运算符优先级上面&&whiletrue&&1的计算结果为1,所以这就是操作的结果。下表按优先级从高(20)到低(1)对算子进行了排序,但这不是最新的,至少不包括可选链,建议参考这张表或MDN。网上的帖子大多是深浅不一,甚至有些不一致。以下文章是对学习过程的总结。如有发现错误,请留言指出。如果本文对您有帮助,别忘了点赞支持哦。你的点赞是我更新最大的动力!
