
1.4.3 逗号运算符
小小的逗号在JavaScript中有很大的用处,一方面它是基本的分隔符,例如,函数传递多个参数时,使用逗号分隔。
console.log('我喜欢去%s上学习%s', '面试厅', 'JavaScript');
另一方面它可以作为一个运算符,作用是将多个表达式连接起来,从左至右依次执行。
逗号作为运算符的表现形式为:表达式1,表达式2,表达式3,……,表达式n。
它的求解过程将按照从左至右的顺序进行,优先执行表达式1,然后执行表达式2……直到执行表达式n,最后返回表达式n的结果。
例如下面的表达式语句。
x = 8 * 2, x * 4
这是一个使用了逗号运算符的语句,首先执行左边的部分,x = 8×2,即x = 16,然后执行右边的语句,x×4 = 16×4 = 64,并将其返回。
这个语句表达的意思是x的值为16,返回的值为“64”。如果将整个语句赋值给一个变量y,则该变量y的值为64。
本小节中我们将重点讲解逗号作为运算符的使用场景。
1. 在for循环中批量执行表达式
逗号运算符在for循环中的使用场景是批量执行表达式。如果一个for循环中有多个变量需要执行表达式,可以通过逗号运算符一次性执行。
for (var i = 0, j = 10; i < 10, j < 20; i++, j++) { console.log(i, j); }
一般在for循环的末尾处,只允许执行单个表达式。在这里我们通过逗号运算符,将i++和j++两个表达式视为同一个表达式,因此可以一次执行,处理i与j两个变量的递增。
2. 用于交换变量,无须额外变量
在我们需要交换两个变量的值时,通常的做法如下所示。
var a = 'a'; var b = 'b'; var c; c = a; a = b; b = c;
借助临时变量c先存储a的值,然后将b值赋给a,再将c值赋给b,这样就可以实现变量交换了。
如果我们不允许使用额外的变量存储,可不可以实现呢?
当然是可以的,这里提供了两种使用逗号运算符的方案。
var a = 'a'; var b = 'b'; // 方案1 a = [b, b = a][0]; // 方案2 a = [b][b = a, 0];
在方案1中,前一部分[b, b = a]是一个一维数组,数组第二项值是b = a,实际会将a值赋给b,然后返回“'a'”,因此数组最终的值为['b', 'a'],然后取索引0的值为'b',赋给变量a,最终实现a = 'b', b = 'a'。
在方案2中,前一部分[b]是一个一维数组,后一部分[b = a, 0],实际会先执行b = a,将a值赋给b,然后返回“0”,因此后一部分实际是修改了b的值并返回索引“0”,最终是a = [b][0],即a = b,实现了a与b的交换。
3. 用于简化代码
因为逗号运算符可以使多个表达式先后执行,并且返回最后一个表达式的值,因此对于某些特定的函数,我们可以使用逗号运算符进行简写。
if (x) { foo(); return bar(); } else { return 1; } // 使用逗号运算符简写后 x ? (foo(), bar()) : 1;
4. 用小括号保证逗号运算符的优先级
在所有的运算符中,逗号运算符的优先级是最低的,因此对于某些涉及优先级的问题,我们需要使用到小括号,将含有逗号运算符的表达式括起来。
var a = 20; var b = ++a, 10; console.log(b); // Uncaught SyntaxError: Unexpected number
对于上面的语句,首先定义一个变量a,然后使用逗号运算符对变量a执行自增操作,同时返回“10”,并将其赋值给变量b。
我们可能会认为最后输出b的值为10,但是运行后却抛出了异常,这是为什么呢?
在上面的代码中,同时出现了赋值运算符与逗号运算符,因为逗号运算符的优先级比较低,实际会先执行赋值运算符,即先执行var b = ++a语句,再去执行后面的10,它不是一个合法的语句,所以会抛出异常。
那么我们该怎么解决这个问题呢?
那就是使用小括号,保证逗号运算符的优先级,将赋值语句后面的内容括起来,执行完含有逗号运算符的表达式后,再执行赋值语句。
var a = 20; var b = (++a, 10); console.log(b); // 10