1. 数值分割符 _web
2. 逗号运算符 ,编程
3. 零合并操做符 ??数组
4. 可选链操做符 ?.浏览器
5. 私有方法/属性安全
6. 位运算符 >> 与 >>>微信
7. 位运算符 & 与 |编辑器
8. 双位运算符 ~~函数
9. 短路运算符 && 与 ||post
10. void 运算符flex
11. 其余经常使用操做符
12. 操做符优先级
JS 里的操做符你们天天都在使用,还有一些 ES2020、ES2021 新加的实用操做符,这些共同构成了 JS 灵活的语法生态。
本文除介绍经常使用的操做符以外,还会介绍 JS 里一些不经常使用可是很强大的操做符,下面咱们一块儿来看看吧~
1. 数值分割符 _
ES2021 引入了数值分割符 _
,在数值组之间提供分隔,使一个长数值读起来更容易。Chrome 已经提供了对数值分割符的支持,能够在浏览器里试起来。
let number = 100_0000_0000_0000 // 0太多了不用数值分割符眼睛看花了
console.log(number) // 输出 100000000000000
此外,十进制的小数部分也可使用数值分割符,二进制、十六进制里也可使用数值分割符。
0x11_1 === 0x111 // true 十六进制
0.11_1 === 0.111 // true 十进制的小数
0b11_1 === 0b111 // true 二进制
2. 逗号运算符 ,
什么,逗号也能够是运算符吗?是的,曾经看到这样一个简单的函数,将数组的第一项和第二项调换,并返回两项之和:
function reverse(arr) {
return [arr[0], arr[1]]=[arr[1], arr[0]], arr[0] + arr[1]
}
const list = [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' // 'default'
null || 'default' // 'default'
false || 'default' // 'default'
0 || 'default' // 'default'
undefined ?? 'default' // 'default'
null ?? 'default' // 'default'
false ?? 'default' // 'false'
0 ?? 'default' // 0
另外在赋值的时候,能够运用赋值运算符的简写 ??=
let a = {b: null, c: 10}
a.b ??= 20
a.c ??= 20
console.log(a) // 输出 { b: 20, c: 10 }
4. 可选链操做符 ?.
可选链操做符 ?.
容许读取位于链接对象链深处的属性的值,而没必要验证链中的每一个引用是否有效。?.
操做符的功能相似于 .
链式操做符,不一样之处在于,在引用为 null
或者 undefined
的状况下不会引发错误,该表达式短路返回值是 undefined
。
当尝试访问可能不存在的对象属性时,可选链操做符将会使表达式更短、更简明。
const obj = {
a: 'foo',
b: {
c: 'bar'
}
}
console.log(obj.b?.c) // 输出 bar
console.log(obj.d?.c) // 输出 undefined
console.log(obj.func?.()) // 不报错,输出 undefined
之前可能会经过 obj && obj.a && obj.a.b
来获取一个深度嵌套的子属性,如今能够直接 obj?.a?.b
便可。
可选链除了能够用在获取对象的属性,还能够用在数组的索引 arr?.[index]
,也能够用在函数的判断 func?.(args)
,当尝试调用一个可能不存在的方法时也可使用可选链。
调用一个对象上可能不存在的方法时(版本缘由或者当前用户的设备不支持该功能的场景下),使用可选链可使得表达式在函数不存在时返回 undefined
而不是直接抛异常。
const result = someInterface.customFunc?.()
5. 私有方法/属性
在一个类里面能够给属性前面增长 #
私有标记的方式来标记为私有,除了属性能够被标记为私有外,getter/setter
也能够标记为私有,方法也能够标为私有。
class Person {
getDesc(){
return this.#name +' '+ this.#getAge()
}
#getAge(){ return this.#age } // 私有方法
get #name(){ return 'foo' } // 私有访问器
#age = 23 // 私有属性
}
const a = new Person()
console.log(a.age) // undefined 直接访问不到
console.log(a.getDesc()) // foo 23
6. 位运算符 >> 与 >>>
有符号右移操做符 >>
将第一个操做数向右移动指定的位数,多余的位移到右边被丢弃,高位补其符号位,正数补 0,负数则补 1。由于新的最左位与前一个最左位的值相同,因此符号位(最左位)不会改变。
(0b111>>1).toString(2) // "11"
(-0b111>>1).toString(2) // "-100" 感受跟直觉不同
正数的好理解,负数怎么理解呢,负数在计算机中存储是按照补码来存储的,补码的计算方式是取反加一,移位时将补码形式右移,最左边补符号位,移完以后再次取反加一求补码得到处理后的原码。
-111 // 真值
1 0000111 // 原码(高位的0无所谓,后面加不到)
1 1111001 // 补码
1 1111100 // 算数右移
1 0000100 // 移位后求补码得到原码
-100 // 移位后的真值
通常咱们用 >>
来将一个数除 2,至关于先舍弃小数位而后进行一次 Math.floor
:
10 >> 1 // 5
13 >> 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) // "1111111111111111111111111111100"
能够这样去理解
-111 // 真值
1 000000000000000000000000000111 // 原码
1 111111111111111111111111111001 // 补码
0 111111111111111111111111111100 // 算数右移(因为右移后成为正数,就不要再求补码了)
1073741820 // 移位后的真值
左移运算符 <<
与之相似,左移很简单左边移除最高位,低位补 0:
(0b1111111111111111111111111111100<<1).toString(2) // "-1000"
(0b1111111111111111111111111111100<<<1).toString(2) // "-1000"
PS:JS 里面没有无符号左移,并且其余语言好比 JAVA 也没有无符号左移。
7. 位运算符 & 与 |
位运算符是按位进行运算,&
与、|
或、~
非、^
按位异或:
&: 1010 |: 1010 ~: 1010 ^: 1010
0110 0110 0110
---- ---- ---- ----
0010 1110 0101 1100
使用位运算符时会抛弃小数位,咱们能够利用这个特性来给数字取整,好比给任意数字 &
上二进制的 32 个 1,或者 |
上 0,显而易见后者简单些。
因此咱们能够对一个数字 | 0
来取整,负数也一样适用
1.3 | 0 // 1
-1.9 | 0 // -1
判断奇偶数除了常见的取余 % 2
以外,也可使用 & 1
,来判断二进制数的最低位是否是 1,这样除了最低位以外都被置 0,取余的结果只剩最低位,是否是很巧妙。负数也一样适用:
const num = 3
!!(num & 1) // true
!!(num % 2) // true
8. 双位运算符 ~~
可使用双位操做符来替代正数的 Math.floor( )
,替代负数的 Math.ceil( )
。双否认位操做符的优点在于它执行相同的操做运行速度更快。
Math.floor(4.9) === 4 // true
// 简写为:
~~4.9 === 4 // true
不过要注意,对正数来讲 ~~
运算结果与 Math.floor( )
运算结果相同,而对于负数来讲与 Math.ceil( )
的运算结果相同:
~~4.5 // 4
Math.floor(4.5) // 4
Math.ceil(4.5) // 5
~~-4.5 // -4
Math.floor(-4.5) // -5
Math.ceil(-4.5) // -4
PS:注意
~~(num/2)
方式和num >> 1
在值为负数时的差异
9. 短路运算符 && 与 ||
咱们知道逻辑与 &&
与逻辑或 ||
是短路运算符,短路运算符就是从左到右的运算中前者知足要求,就再也不执行后者了。
能够理解为:
-
&&
为取假运算,从左到右依次判断,若是遇到一个假值,就返回假值,之后再也不执行,不然返回最后一个真值 -
||
为取真运算,从左到右依次判断,若是遇到一个真值,就返回真值,之后再也不执行,不然返回最后一个假值
let param1 = expr1 && expr2
let param2 = expr1 || expr2

所以能够用来作不少有意思的事,好比给变量赋初值:
let variable1
let variable2 = variable1 || 'foo'
若是 variable1
是真值就直接返回了,后面短路就不会被返回了,若是为假值,则会返回后面的foo
。
也能够用来进行简单的判断,取代冗长的if
语句:
let variable = param && param.prop
// 有了可选链以后能够直接 param?.prop
若是 param
若是为真值则返回 param.prop
属性,不然返回 param
这个假值,这样在某些地方防止 param
为 undefined
的时候还取其属性形成报错。
10. void 运算符
void
运算符 对给定的表达式进行求值,而后返回 undefined
能够用来给在使用当即调用的函数表达式(IIFE)时,能够利用 void
运算符让 JS 引擎把一个 function
关键字识别成函数表达式而不是函数声明。
function iife() { console.log('foo') }() // 报错,由于JS引擎把IIFE识别为了函数声明
void function iife() { console.log('foo') }() // 正常调用
~function iife() { console.log('foo') }() // 也可使用一个位操做符
(function iife() { console.log('foo') })() // 或者干脆用括号括起来表示为总体的表达式
还能够用在箭头函数中避免传值泄漏,箭头函数,容许在函数体不使用括号来直接返回值。这个特性给用户带来了不少便利,但有时候也带来了没必要要的麻烦,若是右侧调用了一个本来没有返回值的函数,其返回值改变后,会致使非预期的反作用。
const func = () => void customMethod() // 特别是给一个事件或者回调函数传一个函数时
安全起见,当不但愿函数返回值是除了空值之外其余值,应该使用 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 === 0 && 1
,- * === &&
这四个运算符优先级最高的 *
先运算,而后 -
运算符结果为 0,===
运算符优先级高于 &&
而 true && 1
的结果为 1,因此这就是运算的结果。
下面的表将运算符按照优先级的不一样从高(20)到低(1)排列,但这个不是最新的,至少没包括可选链,建议参考这个表[1]或者 MDN[2]。

参考文档:
运算符优先级 - JavaScript | MDN [3] JS 中能够提高幸福度的小技巧 [4] 4个未据说过的强大JavaScript操做符 聊聊JavaScript中的二进制数 [5]
PS:本文收录在在下的博客 Github - SHERlocked93/blog[6] 系列文章中,欢迎 star~
参考资料
运算符优先级 - JavaScript | MDN: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Operator_Precedence
[2]JS 中能够提高幸福度的小技巧: https://juejin.cn/post/6844903641468403726
[3]聊聊JavaScript中的二进制数: https://zhuanlan.zhihu.com/p/22297104
本文分享自微信公众号 - 编程微刊(wangxiaoting678)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。