逗号运算符 (,)

逗号 (,) 运算符计算每个操作数(从左到右)并返回最后一个操作数的值。这通常用于为 for 循环的事后想法提供多个更新程序。

¥The comma (,) operator evaluates each of its operands (from left to right) and returns the value of the last operand. This is commonly used to provide multiple updaters to a for loop's afterthought.

Try it

语法

¥Syntax

js
expr1, expr2, expr3/* , … */

参数

¥Parameters

expr1, expr2, expr3, …

一个或多个表达式,最后一个作为复合表达式的值返回。

描述

¥Description

当你想要在需要单个表达式的位置包含多个表达式时,可以使用逗号运算符。该运算符最常见的用法是在 for 循环中提供多个更新程序。

¥You can use the comma operator when you want to include multiple expressions in a location that requires a single expression. The most common usage of this operator is to supply multiple updaters in a for loop.

由于除最后一个表达式之外的所有表达式都会被求值然后被丢弃,因此这些表达式必须具有副作用才能有用。具有副作用的常见表达式有赋值、函数调用以及 ++-- 运算符。其他人如果调用 getters 或触发 类型强制 也可能会产生副作用。

¥Because all expressions except the last are evaluated and then discarded, these expressions must have side effects to be useful. Common expressions that have side effects are assignments, function calls, and ++ and -- operators. Others may also have side effects if they invoke getters or trigger type coercions.

逗号运算符在所有运算符中具有最低的 precedence。如果要将逗号连接的表达式合并到更大的表达式中,则必须将其括起来。

¥The comma operator has the lowest precedence of all operators. If you want to incorporate a comma-joined expression into a bigger expression, you must parenthesize it.

逗号运算符与其他位置用作语法分隔符的逗号完全不同,其中包括:

¥The comma operator is completely different from commas used as syntactic separators in other locations, which include:

  • 数组初始值设定项中的元素 ([1, 2, 3])
  • 对象初始值设定项 ({ a: 1, b: 2 }) 的属性
  • 函数声明/表达式中的参数 (function f(a, b) { … })
  • 函数调用中的参数 (f(1, 2))
  • Binding 列在 letconstvar 声明中 (const a = 1, b = 2;)
  • import 报关单中的导入清单 (import { a, b } from "c";)
  • export 报关单中的出口清单 (export { a, b };)

事实上,虽然其中一些地方接受几乎所有表达式,但它们不接受逗号连接的表达式,因为这与语法逗号分隔符会产生歧义。在这种情况下,你必须将逗号连接的表达式括起来。例如,以下是声明两个变量的 const 声明,其中逗号不是逗号运算符:

¥In fact, although some of these places accept almost all expressions, they don't accept comma-joined expressions because that would be ambiguous with the syntactic comma separators. In this case, you must parenthesize the comma-joined expression. For example, the following is a const declaration that declares two variables, where the comma is not the comma operator:

js
const a = 1, b = 2;

它与下面的不同,其中 b = 2赋值表达式,而不是声明。a 的值是 2,即赋值的返回值,而 1 的值被丢弃:

¥It is different from the following, where b = 2 is an assignment expression, not a declaration. The value of a is 2, the return value of the assignment, while the value of 1 is discarded:

js
const a = (1, b = 2);

逗号运算符不能显示为 尾随逗号

¥Comma operators cannot appear as trailing commas.

示例

¥Examples

在 for 循环中使用逗号运算符

¥Using the comma operator in a for loop

如果 a 是一个每边有 10 个元素的二维数组,则以下代码使用逗号运算符一次性递增 i 并递减 j,从而打印数组中对角线元素的值:

¥If a is a 2-dimensional array with 10 elements on each side, the following code uses the comma operator to increment i and decrement j at once, thus printing the values of the diagonal elements in the array:

js
const a = Array.from({ length: 10 }, () =>
  Array.from({ length: 10 }, Math.random),
); // A 10×10 array of random numbers

for (let i = 0, j = 9; i <= 9; i++, j--) {
  console.log(`a[${i}][${j}] = ${a[i][j]}`);
}

使用逗号运算符连接赋值

¥Using the comma operator to join assignments

因为逗号具有最低的 precedence(甚至低于赋值),所以逗号可用于连接多个赋值表达式。在以下示例中,a 设置为 b = 3 的值(即 3)。然后,c = 4 表达式进行计算,其结果成为整个逗号表达式的返回值。

¥Because commas have the lowest precedence — even lower than assignment — commas can be used to join multiple assignment expressions. In the following example, a is set to the value of b = 3 (which is 3). Then, the c = 4 expression evaluates and its result becomes the return value of the entire comma expression.

js
let a, b, c;

a = b = 3, c = 4; // Returns 4
console.log(a); // 3 (left-most)

let x, y, z;

x = (y = 5, z = 6); // Returns 6
console.log(x); // 6 (right-most)

处理然后返回

¥Processing and then returning

可以使用逗号运算符制作的另一个示例是在返回之前进行处理。如上所述,仅返回最后一个元素,但所有其他元素也将被评估。所以,人们可以这样做:

¥Another example that one could make with the comma operator is processing before returning. As stated, only the last element will be returned but all others are going to be evaluated as well. So, one could do:

js
function myFunc() {
  let x = 0;

  return (x += 1, x); // the same as return ++x;
}

这对于单行 箭头函数 特别有用。以下示例使用单个 map() 来获取数组的总和及其元素的平方,否则需要两次迭代,一次使用 reduce(),一次使用 map()

¥This is especially useful for one-line arrow functions. The following example uses a single map() to get both the sum of an array and the squares of its elements, which would otherwise require two iterations, one with reduce() and one with map():

js
let sum = 0;
const squares = [1, 2, 3, 4, 5].map((x) => ((sum += x), x * x));
console.log(squares); // [1, 4, 9, 16, 25]
console.log(sum); // 15

丢弃引用绑定

¥Discarding reference binding

逗号运算符始终将最后一个表达式作为值而不是引用返回。这会导致一些上下文信息(例如 this 绑定)丢失。例如,属性访问返回对函数的引用,该函数还会记住访问它的对象,以便调用该属性可以正常工作。如果该方法是从逗号表达式返回的,则调用该函数就像它是一个新函数值一样,并且 thisundefined

¥The comma operator always returns the last expression as a value instead of a reference. This causes some contextual information such as the this binding to be lost. For example, a property access returns a reference to the function, which also remembers the object that it's accessed on, so that calling the property works properly. If the method is returned from a comma expression, then the function is called as if it's a new function value, and this is undefined.

js
const obj = {
  value: "obj",
  method() {
    console.log(this.value);
  },
};

obj.method(); // "obj"
(obj.method)(); // "obj" (the grouping operator still returns the reference)
(0, obj.method)(); // undefined (the comma operator returns a new value)

你可以使用此技术输入 间接评估,因为直接 eval 要求函数调用发生在对 eval() 函数的引用上。

¥You can enter indirect eval with this technique, because direct eval requires the function call to happen on the reference to the eval() function.

js
globalThis.isDirectEval = false;

{
  const isDirectEval = true;
  console.log(eval("isDirectEval")); // true
  console.log((eval)("isDirectEval")); // true (the grouping operator still returns a reference to `eval`)
  console.log((0, eval)("isDirectEval")); // false (the comma operator returns a new value)
}

规范

Specification
ECMAScript Language Specification
# sec-comma-operator

¥Specifications

浏览器兼容性

BCD tables only load in the browser

¥Browser compatibility

也可以看看

¥See also