JavaScript运算符优先级

1,314 阅读8分钟

运算符优先级

写在最前

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?.可选链 ES2020x ?. y
17()函数调用myFunction()
17new带参的新建new Date("June 5,2022")
16new不带参的新建new Date()
增量运算符后缀递增在前缀递增之前执行。
15++后缀递增i++
15--后缀递减i--
14++前缀递增++i
14--前缀递减--i
NOT 运算符
14!逻辑非!(x==y)
14~按位非~x
一元运算符
14+一元加+x
14-一元减-x
14typeof数据类型typeof x
14void评估空void(0)
14delete属性删除delete myCar.color
算术运算符指数运算在乘法之前执行。乘法和除法在加法和减法之前执行。
13**指数运算 ES201610 ** 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
关系运算符
9in对象中的属性"PI" in Math
9instanceof对象的实例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??空值合并 ES2020x ?? 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
2yield暂停 / 恢复yield x
2yield*委托运算符yield* x
2...展开运算符... x
1,逗号x , y

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

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