举个栗子:

  1. var a = 42, b;
  2. b = ( a++, a );
  3. a; // 43
  4. b; // 43

如果去掉 ( )

  1. var a = 42, b;
  2. b = a++, a;
  3. a; // 43
  4. b; // 42

原因是 , 运算符的优先级比 = 低。所以 b = a++, a 其实可以理解为 (b = a++), aa++ 有后续副作用(after side effect),所以 b 的值是 ++a 做递增之前的值 42
, 来连接一系列语句的时候,它的优先级最低,其他操作数的优先级都比它高。
之前的栗子:

  1. if (str && (matches = str.match( /[aeiou]/g ))) {
  2. // ..
  3. }

使用( )是必要的,因为&&运算符的优先级高于=,如果没有( )对其中的表达式进行绑定(bind)的话,就会执行作 (str && matches) = str.match..。这样会出错,由于(str && matches)的结果并不是一个变量,而是一个undefined值,因此它不能出现在 = 运算符的左边!

  1. var a = 42;
  2. var b = "foo";
  3. var c = false;
  4. var d = a && b || c ? c || b ? a : c && b : a;
  5. d; // 42

首先我们要搞清楚(a && b || c)执行的是(a && b) || c还是a && (b || c)?它们之间有什么区别?

  1. (false && true) || true; // true
  2. false && (true || true); // false

false && true || true 的执行顺序如下:

  1. false && true || true; // true
  2. (false && true) || true; // true

&& 先执行,然后是 ||
执行顺序不一定是从左到右:

  1. true || false && false; // true
  2. (true || false) && false; // false
  3. true || (false && false); // true

说明 && 运算符先于 || 执行,而且执行顺序并非我们所设想的从左到右。原因就在于运算符优先级。

短路

&&|| 来说,如果从左边的操作数能够得出结果,就可以忽略右边的操作数。将这种现象称为“短路”(即执行最短路径)。
a && b为例,如果a是一个假值,足以决定&&的结果,就没有必要再判断b的值。同样对于 a || b,如果 a 是一个真值,也足以决定 || 的结果,也就没有必要再判断 b 的值。
常见应用:

  1. function doSomething(opts) {
  2. if (opts && opts.cool) {
  3. // ..
  4. }
  5. }
  1. function doSomething(opts) {
  2. if (opts.cache || primeCache()) {
  3. // ..
  4. }
  5. }

更强的绑定

  1. a && b || c ? c || b ? a : c && b : a

执行顺序为:

  1. (a && b || c) ? (c || b) ? a : (c && b) : a

因为 && 运算符的优先级高于 ||,而 || 的优先级又高于 ? :

关联

一般说来,运算符的关联(associativity)不是从左到右就是从右到左,这取决于组合(grouping)是从左开始还是从右开始。关联和执行顺序不是一回事。

  1. a ? b : c ? d : e;

? : 是右关联,所以组合顺序为:

  1. a ? b : (c ? d : e)

&&以及||运算符不同,右关联在这里会影响返回结果, 因为 (a ? b : c) ? d : e 对有些值(并非所有值)的处理方式会有所不同。

  1. true ? false : true ? true : true; // false
  2. true ? false : (true ? true : true); // false
  3. (true ? false : true) ? true : true; // true

在某些情况下,返回的结果没有区别,但其中却有十分微妙的差别

  1. true ? false : true ? true : false; // false
  2. true ? false : (true ? true : false); // false
  3. (true ? false : true) ? true : false; // false

这里返回的结果一样,运算符组合看似没起什么作用。然而实际情况是:

  1. var a = true, b = false, c = true, d = true, e = false;
  2. a ? b : (c ? d : e); // false, 执行 a 和 b
  3. (a ? b : c) ? d : e; // false, 执行 a, b 和 e

另一个右关联(组合)的例子是 = 运算符

  1. var a, b, c;
  2. a = b = c = 42;

它首先执行 c = 42,然后是 b = ..,最后是 a = ..。因为是右关联,所以它实际上是这样来处理的:a = (b = (c = 42))

  1. var a = 42;
  2. var b = "foo";
  3. var c = false;
  4. var d = a && b || c ? c || b ? a : c && b : a;
  5. d; // 42

解析:

  1. ((a && b) || c) ? ((c || b) ? a : (c && b)) : a

(1) (a && b) 结果为 "foo"
(2) "foo" || c 结果为 "foo"
(3) 第一个 ? 中,"foo" 为真值。
(4) (c || b) 结果为 "foo"
(5) 第二个 ? 中,"foo" 为真值。
(6) a 的值为 42