• 首页
  • vue
  • TypeScript
  • JavaScript
  • scss
  • css3
  • html5
  • php
  • MySQL
  • redis
  • jQuery
  • 运算符的优先级

    JavaScript 各种运算符的优先级别(Operator Precedence)是不一样的。优先级高的运算符先执行,优先级低的运算符后执行。

    4 + 5 * 6 // 34
    

    上面的代码中,乘法运算符(*)的优先性高于加法运算符(+),所以先执行乘法,再执行加法,相当于下面这样。

    4 + (5 * 6) // 34
    

    如果多个运算符混写在一起,常常会导致令人困惑的代码。

    var x = 1;
    var arr = [];
    
    var y = arr.length <= 0 || arr[0] === undefined ? x : arr[0];
    

    上面代码中,变量y的值就很难看出来,因为这个表达式涉及5个运算符,到底谁的优先级最高,实在不容易记住。

    根据语言规格,这五个运算符的优先级从高到低依次为:小于等于(<=)、严格相等(===)、或(||)、三元(?:)、等号(=)。因此上面的表达式,实际的运算顺序如下。

    var y = ((arr.length <= 0) || (arr[0] === undefined)) ? x : arr[0];
    

    记住所有运算符的优先级,是非常难的,也是没有必要的。


    执行顺序优先级从高到低:

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


    执行顺序优先级:自上而下,由最高到最低。具有相同优先级的运算符按从左至右的顺序求值
    运算符结合描述
    .[]()从左到右字段访问、数组下标、函数调用以及表达式分组
    ++---~!deletenewtypeofvoid从右到左一元运算符、返回数据类型、对象创建、未定义值
    **从右到左幂运算
    */%从左到右乘法、除法、取模
    +-+从左到右加法、减法、字符串连接
    <<>>>>>从左到右移位
    <<=>>=instanceof从左到右小于、小于等于、大于、大于等于、instanceof
    ==!====!==从左到右等于、不等于、严格相等、非严格相等
    &从左到右按位与
    ^从左到右按位异或
    |从左到右按位或
    &&从左到右逻辑与
    ||从左到右逻辑或
    ?:从左到右三目运算
    >=oP=从右到左赋值、运算赋值
    ,从左到右多重求值


    圆括号的作用

    圆括号()可以用来提高运算的优先级,因为它的优先级是最高的,即圆括号中的表达式会第一个运算。

    (4 + 5) * 6 // 54
    

    上面代码中,由于使用了圆括号,加法会先于乘法执行。

    运算符的优先级别十分繁杂,且都是硬性规定,因此建议总是使用圆括号,保证运算顺序清晰可读,这对代码的维护和除错至关重要。

    顺便说一下,圆括号不是运算符,而是一种语法结构。它一共有两种用法:一种是把表达式放在圆括号之中,提升运算的优先级;另一种是跟在函数的后面,作用是调用函数。

    注意,因为圆括号不是运算符,所以不具有求值作用,只改变运算的优先级。

    var x = 1;
    (x) = 2;
    

    上面代码的第二行,如果圆括号具有求值作用,那么就会变成1 = 2,这是会报错了。但是,上面的代码可以运行,这验证了圆括号只改变优先级,不会求值。

    这也意味着,如果整个表达式都放在圆括号之中,那么不会有任何效果。

    (expression)
    // 等同于
    expression
    

    函数放在圆括号中,会返回函数本身。如果圆括号紧跟在函数的后面,就表示调用函数。

    function f() {
      return 1;
    }
    
    (f) // function f(){return 1;}
    f() // 1
    

    上面代码中,函数放在圆括号之中会返回函数本身,圆括号跟在函数后面则是调用函数。

    圆括号之中,只能放置表达式,如果将语句放在圆括号之中,就会报错。

    (var a = 1)
    // SyntaxError: Unexpected token var
    


    左结合与右结合

    对于优先级别相同的运算符,同时出现的时候,就会有计算顺序的问题。

    a OP b OP c
    

    上面代码中,OP表示运算符。它可以有两种解释方式。

    // 方式一
    (a OP b) OP c
    
    // 方式二
    a OP (b OP c)
    

    上面的两种方式,得到的计算结果往往是不一样的。方式一是将左侧两个运算数结合在一起,采用这种解释方式的运算符,称为“左结合”(left-to-right associativity)运算符;方式二是将右侧两个运算数结合在一起,这样的运算符称为“右结合”运算符(right-to-left associativity)。

    JavaScript 语言的大多数运算符是“左结合”,请看下面加法运算符的例子。

    x + y + z
    
    // 引擎解释如下
    (x + y) + z
    

    上面代码中,xy结合在一起,它们的预算结果再与z进行运算。

    少数运算符是“右结合”,其中最主要的是赋值运算符(=)和三元条件运算符(?:)。

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

    上面代码的解释方式如下。

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

    上面的两行代码,都是右侧的运算数结合在一起。

    另外,指数运算符(**)也是右结合。

    2 ** 3 ** 2
    // 相当于 2 ** (3 ** 2)
    // 512
    

    上篇:逗号运算符