欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

理解JavaScript中的运算符优先级规则

最编程 2024-08-05 12:48:21
...

运算符优先级

写在最前

js 代码如下,请问在控制台中输出的结果为?

var a = "hello"
console.log("This is "  + (a== "hello") ? 'Mine' : 'Yours')

如果先入为主求结果的话,我们很容易就想到输出结果为:This is Mine。当我们这么想时,我们其实就已经掉入了出题者设计的大坑中了~该题考察的是运算符优先级,我们细分此题计算过程:

Step1:括号改变优先级,因此先算括号里面的值,得到结果:"This is ” + true ? 'Mine' : ‘Yours’

Step2:+ 的优先级要高于 ?:,因此先算 + 号,得到结果:"This is true" ? 'Mine' : ‘Yours’

Step3:计算? : 由于前面的字符串不为空,转为 bool 值为true,因此,整个表达式的结果为 Mine;

综上所述,此题的运行结果为 Mine

JavaScript运算符优先级

JavaScript运算符均有明确的优先级与结合性。优先级较高的运算符将先于优先级较低的运算符进行运算。结合性是指具有同等优先级的运算符将按照怎样的顺序进行运算。结合性有向左结合和向右结合两种。

例如,表达式a+b+c,向左结合就是先计算a+b,即(a+b)+c;而向右结合就是先计算b+c,即a+(b+c)

运算符优先级从高到低:

  1. 圆括号运算符:(),优先级最高
  2. 一元运算符:++--!
  3. 算数运算符:先*/%,后+-
  4. 关系运算符:<<=>>=
  5. 相等运算符:==!====!==
  6. 逻辑运算符:先&&,后||
  7. 三目运算符:?:
  8. 赋值运算符:=
  9. 逗号运算符:,

圆一算关、相逻三赋逗!

下表按从最高到最低的优先级列出JavaScript运算符,具有相同优先级的运算符按从左至右的顺序求值。

优先级 分类 运算符 结合性
1 后缀运算符 ( )、[ ]、-> 从左到右
2 单目运算符 !、*(指针)、& 、++、--、+(正号)、-(负号) 从右到左
3 乘法/除法/取余 *(乘号)、/、% 从左到右
4 加法/减法 +、- 从左到右
5 位移运算符 <<、>> 从左到右
6 关系运算符 <、<=、>、>= 从左到右
7 相等/不等 ==、!= 从左到右
8 按位与 & 从左到右
9 按位异或 ^ 从左到右
10 按位或 | 从左到右
11 逻辑与 && 从左到右
12 逻辑或 || 从左到右
13 三目运算符 ? : 从右到左
14 赋值运算符 =、+=、-=、*=、/=、 %=、 >>=、 <<=、&=、^=、|= 从右到左
15 逗号运算符 , 从左到右

小试牛刀

  1. 案例1(小括号 与 算术运算符)

    var a = 1 + 2 * 3 //7
    var b = 10 - 2 / 4 //9.5
    console.log(`a = ${a}, b = ${b}`) //a = 7, b = 9.5
    var a = (1 + 2) * 3 //9
    var b = (10 - 2) / 4 //2
    console.log(`a = ${a}, b = ${b}`) //a = 9, b = 2
    

    括号运算符>算数运算符,并且结合性均为从左到右

  2. 案例2(小括号 与 逻辑运算符、关系运算符 与 逻辑运算符)

    a || b * c // 首先对 `a` 求值,如果 `a` 为真值则直接返回 `a`
    a && b < c // 首先对 `a` 求值,如果 `a` 为虚值则直接返回 `a`
    a ?? (b || c) // 首先对 `a` 求值,如果 `a` 不是 `null` 或 `undefined` 则直接返回 `a`
    //a?.b.c   // 首先对 `a` 求值,如果 `a` 是 `null` 或 `undefined` 则直接返回 `undefined`
    
    3 > 2 && 2 > 1 // 返回 true,此处相当于true && true
    3 > 2 > 1 
    // 返回 false,因为 3 > 2 是 true,然后 true 会在比较运算符中被隐式转换为 1
    // 因此 true > 1 会变为 1 > 1,结果是 false
    // 加括号可以更清楚:(3 > 2) > 1
    

    括号运算符>算数运算符>逻辑运算符,并且结合性为从左到右

  3. 案例3(关系运算符、相等运算符、三目运算符混用)

    let x = 1
    let arr = []
    let y = arr.length <= 0 || arr[0] === undefined ? x : arr[0]
    console.log(y) //1
    //1.先计算最左边arr.length <= 0,为true
    //2.再计算arr[0] === undefined,为true
    //3.再计算true||true?x:arr[0]的最左边
    //4.最后计算true?x:arr[0]
    //5.最终结果为y = x,即y = 1
    

    关系运算符 >相等运算符>三目运算符,并且结合性为从左到右

  4. 案例4(结合性)

    w = x = y = z  //w = (x = (y = z))
    q = a ? b : c ? d : e ? f : g  //q = a ? b : (c ? d : (e ? f : g));
    

    三目运算符>赋值运算符,并且结合性为从右到左

  5. 案例5(逻辑运算符)

    • 短路运算,即运算符两端的两个逻辑表达式,当第一个逻辑表达式不符合条件时,就会得出结果,不会再去计算第二个逻辑表达式
    • 当逻辑表达式不是布尔值的结果时,会进行隐式转换为布尔值,但是最后运算结果,返回的不是布尔值,而是进行隐式转换之前的原结果(大坑)
    console.log(1 || 2) //1,此处为或运算,左边为true,逻辑中断,不用计算右边,直接输出或运算符左边的原结果,即1
    console.log(1 || 0) //1,此处为或运算,左边为true,逻辑中断,不用计算右边,直接输出或运算符左边的原结果,即1
    console.log(0 || 1) //1,此处为或运算,左边为false,右边计算为true,输出或运算符右边的原结果,即1
    console.log(0 || 0) //0,此处为或运算,左边为false,右边计算为false,输出或运算符右边的原结果,即0
    console.log(1 && 2) //2,此处为与运算,左边为true,右边计算为true,输出与运算符右边的原结果,即2
    console.log(1 && 0) //0,此处为与运算,左边为true,右边计算为false,输出与运算符右边的原结果,即0
    console.log(0 && 1) //0,此处为与运算,左边为false,逻辑中断,不用计算右边,直接输出与运算符左边的原结果,即0
    
    //实际例子举例
    let age = 10;
    console.log(true && age++); //10,++在右边,不参与运算
    console.log(true && ++age); //12,++在左边,参与运算
    console.log(age); //12
    
    console.log(true || false && false) // true
    //这是一个很经典的例子,如果我们不知道 && 的优先级比 || 高,我们肯定以为返回值是false
    

    逻辑与>逻辑或,并且结合性为从左到右

  6. 案例6(三目运算符 与 逻辑与)

    console.log(1 && 0 ? 3 : 2) // 2
    //&&的运算级比三目运算符更高,先计算&&
    

    逻辑与>三目运算符,且逻辑与结合性为从左到右,三目运算符结合性为从右到左

  7. 案例7(typeof 与 三目运算符)

    let flag = false
    console.log(typeof flag) // boolean
    console.log(typeof flag ? '2' : 1) // 2,此处?前面的typeof flag值为boolean,为一个字符串,隐式转换为true
    

    typeof>三目运算符,typeof结合性为从左到右,三目运算符结合性为从右到左

  8. 案例8(三目运算符 与 相等运算符==)

    let value = "3"
    let index = 3
    let flag = value == index ? 1 : 2
    //1.先算value == index,结果为true
    //2.再计算 true ? 1 : 2,结果为1
    //3.最后赋值给flag,即flag=1
    console.log(flag) // 1
    

    相等运算符==>三目运算符>赋值运算符,赋值运算符与相等运算符结合性为从左到右,三目运算符结合性为从右到左

总结

运算符优先级小结:

Snipaste_2023-05-16_07-08-13.png

后缀运算符>一元运算符>算数运算符>关系运算符>相等运算符>逻辑运算符>三目运算符>赋值运算符>逗号运算符

附录

运算符优先级一览表:

优先级 运算符 描述 例子
18 ( ) 表达式分组 (100 + 50) * 3
17 . 属于成员 person.name
17 [] 属于成员 person["name"]
17 ?. 可选链 ES2020 x ?. y
17 () 函数调用 myFunction()
17 new 带参的新建 new Date("June 5,2022")
16 new 不带参的新建 new Date()
增量运算符后缀递增在前缀递增之前执行。
15 ++ 后缀递增 i++
15 -- 后缀递减 i--
14 ++ 前缀递增 ++i
14 -- 前缀递减 --i
NOT 运算符
14 ! 逻辑非 !(x==y)
14 ~ 按位非 ~x
一元运算符
14 + 一元加 +x
14 - 一元减 -x
14 typeof 数据类型 typeof x
14 void 评估空 void(0)
14 delete 属性删除 delete myCar.color
算术运算符指数运算在乘法之前执行。乘法和除法在加法和减法之前执行。
13 ** 指数运算 ES2016 10 ** 2
12 * 10 * 5
12 / 10 / 5
12 % 除法余数 10 % 5
11 + 10 + 5
11 - 10 - 5
11 + 串联 "Bill" + "Gates"
移位运算符
10 << 左移 x << 2
10 >> 右移(带符号) x >> 2
10 >>> 右移(无符号) x >>> 2
关系运算符
9 in 对象中的属性 "PI" in Math
9 instanceof 对象的实例 x instanceof Array
比较运算符
9 < 小于 x < y
9 <= 小于或等于 x <= y
9 大于 x > y
9 >= 大于或等于 x >= Array
8 == 等于 x == y
8 === 严格相等 x === y
8 != 不相等 x != y
8 !== 严格不相等 x !== y
位运算符
7 & 按位与 x & y
6 按位异或 x ^ y
5 | 按位或 x | y
逻辑运算符
4 && 逻辑与 x && y
3 || 逻辑或 x || y
3 ?? 空值合并 ES2020 x ?? y
条件(三元)运算符
2 ? : 条件 ? "yes" : "no"
赋值运算符赋值在其他操作之后执行。
2 = 简单赋值 x = y
2 : 冒号赋值 x: 5
2 += 加法赋值 x += y
2 -= 减法赋值 x -= y
2 *= 乘法赋值 x *= y
2 **= 指数赋值 x **= y
2 /= 除法赋值 x /= y
2 %= 取余赋值 x %= y
2 <<= 左移赋值 x <<= y
2 >>= 右移赋值 x >>= y
2 >>>= 无符号右移 x >>>= y
2 &= 位与赋值 x &= y
2 |= 位或赋值 x |= y
2 ^= 位异或赋值 x ^= y
2 &&= 逻辑与赋值 x &= y
2 ||= 逻辑或赋值 x ||= y
2 => 箭头 x => y
2 yield 暂停 / 恢复 yield x
2 yield* 委托运算符 yield* x
2 ... 展开运算符 ... x
1 , 逗号 x , y

注:本文举例均来自于互联网

优先级官方定义文档跳转:w3schoolMDN