前言

JS中的表达式非常强大,对应的是与表达式相关的各种运算符,这些运算符能够任意组合,赋予JS极大的灵活性和强大的组合性,很多时候用运算符就可代替许多用数行语句才能实现的功能,在这运算符强大的背后,隐藏着优先级带来的隐患
大多JS开发者对于运算符的优先级并不非常熟悉,这导致了如果肆意使用运算符,就可能因为优先级而导致诸多问题,甚至造成实际生产事故,所以,在拥抱运算符带来的强大力量的同时,运算符带来的潜在的危险性也不容忽视

例子

一个例子

我们可能之前有以下老代码

// Order 是一个构造函数,用于创建订单
function Order {
    // 一些代码
}
// 如果 order 是 Order 的实例,做一些事,否则,做一些事
if(order instanceof Order) {
    // 一些代码
}

业务变了,现在需要在 order 不是 Order 的实例的情况下做一些事
对于新手可能会这么写

if(order instanceof Order) {
}else {
    // 一些代码
}

这运行起来是正确的,但是条件为true的块就空了,很不优雅
因此熟悉运算符的人有可能会这么写

if(!order instanceof Order) {
    // 一些代码
}
陷阱

对于这段代码的执行
参考下面的测试用例

let order = new Order();
// 我们的代码
!order instanceof Order // false
// 我们期望的执行时的优先级
!(order instanceof Order) // false

目前,看起来是正确的
但是,如果是下面这个用例

let order = {};
// 我们的代码
!order instanceof Order // false
// 我们期望的执行时的优先级
!(order instanceof Order) // true

这产生了不同的结果,尚未使用圆括号包裹不同的运算符,这可能导致问题,因为 ! 的优先级高于 instanceof
所以上述表达式实际上是这样运行的

(!order) instanceof Order;

这个表达式始终返回 false
而我们期望在 order 不为 Order 实例的时候返回 true, 否则 false
所以,对于上述情况,必须要手动添加括号确保优先级

!(order instanceof Order);

上述情况是个常见的例子,我们经常会使用 !xxx, !xx() !xx.xx[xx]() ,因此就可能出现上述问题

两个其他的例子

运算符 ! typeof 和 ===

参考以下代码

// 表达式1
typeof a === "string"
// 和 表达式2
!typeof a === "string"

常规用法,我们知道, typeof 的优先级大于 === 的优先级所以我们知道第一个表达式是这样执行的

(typeof a) === "string"

实际上 ! 的优先级和 typeof 的优先级相同, 但是大于 === 的优先级
所以上述表达式2实际是这样的

(!(typeof a)) === "string"

而我们期望的执行是这样的

!((typeof a) === "string")

对于上述情况,建议改用 !== 运算符,这样就不必在前面使用 ! ,也不必考虑优先级问题,如果确实出现了类似情况需要前面加 ! ,确保加上圆括号

逻辑运算符 && || ??

对于这三者,如果不熟悉的话可能会认为优先级相同,这可能会导致如下代码

a && b && c || d

因为 && 优先级高于 ||, 所以上述代码实际执行的优先级是,

(a && b && c) || d

这有可能不符合预期,有些时候我们的预期是这样的

a && b && (c || d)

对于这种情况,必须加上圆括号以确保优先级
对于 ?? 运算符,我们可以看作和 || 是相同类型,都是在左侧不符合条件的时候使用右侧
实际上这三者的优先级是 && 高于 || 和 ??, || 和 ?? 是相同的优先级

参考

mdn web docs 运算符优先级

结语

我建议大多数时候在不同的运算符结合使用时添加圆括号
如果一眼不能看出优先级高低,最好添加圆括号确定优先级


Error4767
64 声望3 粉丝