其他运算符,运算顺序

    上面是void运算符的两种写法,都正确。建议采用后一种形式,即总是使用圆括号。因为void运算符的优先性很高,如果不使用括号,容易造成错误的结果。比如,void 4 + 7实际上等同于(void 4) + 7

    下面是void运算符的一个例子。

    1. var x = 3;
    2. void (x = 5) //undefined
    3. x // 5

    这个运算符的主要用途是浏览器的书签工具(Bookmarklet),以及在超级链接中插入代码防止网页跳转。

    请看下面的代码。

    1. <script>
    2. function f() {
    3. console.log('Hello World');
    4. }
    5. </script>
    6. <a href="http://example.com" onclick="f(); return false;">点击</a>

    上面代码中,点击链接后,会先执行onclick的代码,由于onclick返回false,所以浏览器不会跳转到 example.com。

    void运算符可以取代上面的写法。

    1. <a href="javascript: void(f())">文字</a>

    下面是一个更实际的例子,用户点击链接提交表单,但是不产生页面跳转。

    1. <a href="javascript: void(document.form.submit())">
    2. 提交

    逗号运算符用于对两个表达式求值,并返回后一个表达式的值。

    1. 'a', 'b' // "b"
    2. var y = (x++, 10);
    3. x // 1
    4. y // 10

    上面代码中,逗号运算符返回后一个表达式的值。

    逗号运算符的一个用途是,在返回一个值之前,进行一些辅助操作。

    1. var value = (console.log('Hi!'), true);
    2. // Hi!
    3. value // true

    上面代码中,先执行逗号之前的操作,然后返回逗号后面的值。

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

    1. 4 + (5 * 6) // 34

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

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

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

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

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

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

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

    1. (4 + 5) * 6 // 54

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

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

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

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

    1. var x = 1;

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

    1. (expression)
    2. // 等同于
    3. expression

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

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

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

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

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

    1. a OP b OP c

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

    1. // 方式一
    2. (a OP b) OP c
    3. // 方式二
    4. a OP (b OP c)

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

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

    1. x + y + z
    2. // 引擎解释如下
    3. (x + y) + z

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

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

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

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

    1. w = (x = (y = z));

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