举个栗子:
var a = 42, b;
b = ( a++, a );
a; // 43
b; // 43
如果去掉 ( )
var a = 42, b;
b = a++, a;
a; // 43
b; // 42
原因是 , 运算符的优先级比 =
低。所以 b = a++, a
其实可以理解为 (b = a++), a
。 a++
有后续副作用(after side effect),所以 b
的值是 ++
对 a
做递增之前的值 42
。
用 ,
来连接一系列语句的时候,它的优先级最低,其他操作数的优先级都比它高。
之前的栗子:
if (str && (matches = str.match( /[aeiou]/g ))) {
// ..
}
使用( )
是必要的,因为&&
运算符的优先级高于=
,如果没有( )
对其中的表达式进行绑定(bind)的话,就会执行作 (str && matches) = str.match..
。这样会出错,由于(str && matches)
的结果并不是一个变量,而是一个undefined
值,因此它不能出现在 =
运算符的左边!
var a = 42;
var b = "foo";
var c = false;
var d = a && b || c ? c || b ? a : c && b : a;
d; // 42
首先我们要搞清楚(a && b || c)
执行的是(a && b) || c
还是a && (b || c)?
它们之间有什么区别?
(false && true) || true; // true
false && (true || true); // false
false && true || true
的执行顺序如下:
false && true || true; // true
(false && true) || true; // true
&&
先执行,然后是 ||
。
执行顺序不一定是从左到右:
true || false && false; // true
(true || false) && false; // false
true || (false && false); // true
说明 &&
运算符先于 ||
执行,而且执行顺序并非我们所设想的从左到右。原因就在于运算符优先级。
短路
对 &&
和 ||
来说,如果从左边的操作数能够得出结果,就可以忽略右边的操作数。将这种现象称为“短路”(即执行最短路径)。
以a && b
为例,如果a
是一个假值,足以决定&&
的结果,就没有必要再判断b
的值。同样对于 a || b
,如果 a
是一个真值,也足以决定 ||
的结果,也就没有必要再判断 b
的值。
常见应用:
function doSomething(opts) {
if (opts && opts.cool) {
// ..
}
}
function doSomething(opts) {
if (opts.cache || primeCache()) {
// ..
}
}
更强的绑定
a && b || c ? c || b ? a : c && b : a
执行顺序为:
(a && b || c) ? (c || b) ? a : (c && b) : a
因为 &&
运算符的优先级高于 ||
,而 ||
的优先级又高于 ? :
。
关联
一般说来,运算符的关联(associativity)不是从左到右就是从右到左,这取决于组合(grouping)是从左开始还是从右开始。关联和执行顺序不是一回事。
a ? b : c ? d : e;
? :
是右关联,所以组合顺序为:
a ? b : (c ? d : e)
和&&
以及||
运算符不同,右关联在这里会影响返回结果, 因为 (a ? b : c) ? d : e
对有些值(并非所有值)的处理方式会有所不同。
true ? false : true ? true : true; // false
true ? false : (true ? true : true); // false
(true ? false : true) ? true : true; // true
在某些情况下,返回的结果没有区别,但其中却有十分微妙的差别
true ? false : true ? true : false; // false
true ? false : (true ? true : false); // false
(true ? false : true) ? true : false; // false
这里返回的结果一样,运算符组合看似没起什么作用。然而实际情况是:
var a = true, b = false, c = true, d = true, e = false;
a ? b : (c ? d : e); // false, 执行 a 和 b
(a ? b : c) ? d : e; // false, 执行 a, b 和 e
另一个右关联(组合)的例子是 =
运算符
var a, b, c;
a = b = c = 42;
它首先执行 c = 42
,然后是 b = ..
,最后是 a = ..
。因为是右关联,所以它实际上是这样来处理的:a = (b = (c = 42))
。
var a = 42;
var b = "foo";
var c = false;
var d = a && b || c ? c || b ? a : c && b : a;
d; // 42
解析:
((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
。