recursal/MDN huggingface dataset:
取余（%）
=====

**取余**（**`%`**）运算符返回左侧操作数除以右侧操作数的余数。它总是与被除数的符号保持一致。

尝试一下
----

语法
--


```js
x % y
```

描述
--

对于运算：`n % d`，其中 `n` 被称为被除数，`d` 被称为除数。如果其中的任意一个操作数为 `NaN`，或 `n` 为正负无穷（±Infinity），又或者 `d` 为 ±0，则该运算返回 `NaN`。否则，如果 `d` 为正负无穷（±Infinity），或 `n` 为 ±0，则返回被除数 `n`。

如果两个操作数都非零且有限（非正负无穷）时，余数 `r` 将通过 `r := n - d * q` 计算获得，其中 `q` 是一个使得 `r` 与被除数 `n` 具有相同符号，并且会使 `r` 尽可能地接近于 0 的整数。

请注意，虽然在大多数语言中，`%` 是取余运算符，但在某些语言（例如：Python 和 Perl）中，它是取模运算符。取模运算被定义为 `k := n - d * q`，其中 `q` 是一个使得 `k` 与除数具有相同符号，并且会使 `k` 尽可能地接近于 0 的整数。对于同号的两根操作数，两者是等价的，但在操作数具有不同的符号时，取模运算的结果总是与*除数*同号，而取余运算则是余数与*被除数*同号，`d` 的符号即可使两者的结果不相同。为了在 JavaScript 中使用 `n % d` 实现取模运算，可以使用 `((n % d) + d) % d`。在 JavaScript 中，模运算（没有专用的运算符）用于规范化按位移位运算符（`<<`、`>>`，等等）的第二个操作数，以使得偏移量始终为一个正数。

示例
--

### 被除数为正数


```js
13 % 5; // 3
1 % -2; // 1
1 % 2; // 1
2 % 3; // 2
5.5 % 2; // 1.5
```

### 被除数为负数


```js
-13 % 5; // -3
-1 % 2; // -1
-4 % 2; // -0
```

### 被除数为 NaN


```js
NaN % 2; // NaN
```

### 被除数为 Infinity


```js
Infinity % 2; // NaN
Infinity % 0; // NaN
Infinity % Infinity; // NaN
2 % Infinity; // 2
0 % Infinity; // 0
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-multiplicative-operators |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* 加法运算符
* 减法运算符
* 除法运算符
* 乘法运算符
* 幂运算符
* 自增运算符
* 自减运算符
* 一元减运算符
* 一元加运算符
* 取余运算和取模运算的区别
乘法赋值（\*=）
=========

**乘法赋值**（**`*=`**）运算符将变量乘以右操作数的值，并将结果赋值给该变量。

尝试一下
----

语法
--


```js
x \*= y // x = x \* y
```

示例
--

### 使用乘法赋值


```js
let bar = 5;

bar \*= 2; // 10
bar \*= "foo"; // NaN
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-assignment-operators |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* JS 指南中的赋值操作符
* 乘法运算符
empty
=====

**空语句**用来表明没有语句，尽管 JavaScript 语法希望有语句。

语法
--
```

;
```

描述
--

空语句是一个分号（;），表示不会执行任何语句，即使 JavaScript 语法需要一个语句。相反，当你需要多行语句，但 JavaScript 只允许一个时，可以使用语句块；语句块可以将多条语句合并为一个。

示例
--

空语句有时与循环语句一起使用。以下示例使用空循环体：


```js
var arr = [1, 2, 3];

// Assign all array values to 0
for (let i = 0; i < arr.length; arr[i++] = 0 /\* empty statement \*/);

console.log(arr);
// [0, 0, 0]
```


\*\*提示：\*\*在使用空语句的情况下专门写上注释是个不错的主意，因为不是很容易区分空语句和普通的分号。下面的示例可能不是故意加上分号的：


```js
if (condition); // Caution, this "if" does nothing!
  killTheUniverse() // So this gets always executed!!!
```


另一个例子：`if...else` 语句不带花括号（`{}`）。如果`three`为`true`, 不会发生任何事，`four`不会执行，同时`else`从句中的`launchRocket()`函数也不会执行。


```js
if (one)
  doOne();
else if (two)
  doTwo();
else if (three)
  ; // nothing here
else if (four)
  doFour();
else
  launchRocket();
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-empty-statement |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* `块语句`
for
===

**`for` 语句**用于创建一个循环，它包含了三个可选的表达式，这三个表达式被包围在圆括号之中，使用分号分隔，后跟一个用于在循环中执行的语句（通常是一个块语句）。

尝试一下
----

语法
--
```

for ([initialization]; [condition]; [final-expression])
   statement
```


`initialization`

一个表达式 (包含赋值语句) 或者变量声明。典型地被用于初始化一个计数器。该表达式可以使用 `var` 或 `let` 关键字声明新的变量，使用 `var` 声明的变量不是该循环的局部变量，而是与 `for` 循环处在同样的作用域中。用 `let` 声明的变量是语句的局部变量。该表达式的结果无意义。

`condition`

一个条件表达式被用于确定每一次循环是否能被执行。如果该表达式的结果为 true，`statement` 将被执行。这个表达式是可选的。如果被忽略，那么就被认为永远为真。如果计算结果为假，那么执行流程将被跳到 `for` 语句结构后面的第一条语句。

`final-expression`

每次循环的最后都要执行的表达式。执行时机是在下一次 `condition` 的计算之前。通常被用于更新或者递增计数器变量。

`statement`

只要`condition`的结果为 true 就会被执行的语句。要在循环体内执行多条语句，使用一个块语句（`{ ... }`）来包含要执行的语句。没有任何语句要执行，使用一个空语句（`;`）。

示例
--

### 使用 `for`

以下例子声明了变量 `i` 并被初始赋值为 `0`，`for` 语句检查 `i` 的值是否小于 9，如果小于 9，则执行语句块内的语句，并且最后将 `i` 的值增加 1。


```js
for (var i = 0; i < 9; i++) {
  console.log(i);
  // more statements
}
```

### 可选的 `for` 表达式

`for` 语句头部圆括号中的所有三个表达式都是可选的。

例如，初始化块中的表达式没有被指定：


```js
var i = 0;
for (; i < 9; i++) {
  console.log(i);
  // more statements
}
```


像初始化块一样，条件块也是可选的。如果省略此表达式，则必须确保在循环体内跳出，以防创建死循环。


```js
for (var i = 0; ; i++) {
  console.log(i);
  if (i > 3) break;
  // more statements
}
```


你当然可以忽略所有的表达式。同样的，确保使用了 `break` >语句来跳出循环并且还要修改（增加）一个变量，使得 break 语句的条件在某个时候是真的。


```js
var i = 0;

for (;;) {
  if (i > 3) break;
  console.log(i);
  i++;
}
```

### 使用无语句的 `for`

以下 `for` 循环计算 *final-expression* 部分中节点的偏移位置，它不需要执行一个 `statement` 或者一组 `block statement` ，因此使用了空语句。


```js
function showOffsetPos(sId) {
  var nLeft = 0,
    nTop = 0;

  for (
    var oItNode = document.getElementById(sId) /\* initialization \*/;
    oItNode /\* condition \*/;
    nLeft += oItNode.offsetLeft,
      nTop += oItNode.offsetTop,
      oItNode = oItNode.offsetParent /\* final-expression \*/
  ); /\* 分号 semicolon \*/

  console.log(
    "Offset position of '" +
      sId +
      "' element:\n left: " +
      nLeft +
      "px;\n top: " +
      nTop +
      "px;",
  );
}

/\* Example call: \*/

showOffsetPos("content");

// Output:
// "Offset position of "content" element:
// left: 0px;
// top: 153px;"
```


**备注：** **这里的分号是强制性的**，是 JavaScript 中的少数几种强制分号的情况。如果没有分号，循环声明之后的行将被视为循环语句。

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-for-statement |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* empty statement
* `break`
* `continue`
* `while`
* `do...while`
* `for...in`
* `for...of`
if...else
=========

当指定条件为真，**if 语句**会执行一段语句。如果条件为假，则执行另一段语句。

尝试一下
----

语法
--
```

if (condition)
   statement1
[else
   statement2]
```


`condition`

值为真或假的表达式

`statement1`

当`condition`为真时执行的语句。可为任意语句，包括更深层的内部`if`语句。要执行多条语句，使用块语句（{ ... }）将这些语句分组；若不想执行语句，则使用空语句。

`statement2`

如果`condition`为假且 `else`从句存在时执行的语句。可为任意语句，包括块语句和嵌套的`if`语句。

说明
--

多层 `if...else` 语句可使用 `else if` 从句。注意：在 Javascript 中没有 `elseif` （一个单词）关键字。
```

if (condition1)
   statement1
else if (condition2)
   statement2
else if (condition3)
   statement3
...
else
   statementN
```


要看看它如何工作，可以调整下嵌套的缩进：
```

if (condition1)
   statement1
else
   if (condition2)
      statement2
   else
      if (condition3)
...
```


要在一个从句中执行多条语句，可使用语句块（`{ ... }`）。通常情况下，一直使用语句块是个好习惯，特别是在涉及嵌套`if`语句的代码中：
```

if (condition) {
   statements1
} else {
   statements2
}
```


不要将原始布尔值的`true`和`false`与Boolean对象的真或假混淆。任何一个值，只要它不是 `undefined`、`null`、 `0`、`NaN`或空字符串（`""`），那么无论是任何对象，即使是值为假的 Boolean 对象，在条件语句中都为真。例如：


```js
var b = new Boolean(false);
if (b) //表达式的值为 true
```

示例
--

### 使用 `if...else`


```js
if (cipher_char === from_char) {
  result = result + to_char;
  x++;
} else {
  result = result + clear_char;
}
```

### 使用 `else if`

注意，Javascript 中没有`elseif`语句。但可以使用`else`和`if`中间有空格的语句：


```js
if (x > 5) {
  /\* do the right thing \*/
} else if (x > 50) {
  /\* do the right thing \*/
} else {
  /\* do the right thing \*/
}
```

### 条件表达式中的赋值运算

建议不要在条件表达式中单纯的使用赋值运算，因为粗看下赋值运算的代码很容易让人误认为是等性比较。比如，不要使用下面示例的代码：


```js
if (x = y) {
  /\* do the right thing \*/
}
```


如果你需要在条件表达式中使用赋值运算，用圆括号包裹赋值运算。例如：


```js
if ((x = y)) {
  /\* do the right thing \*/
}
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-if-statement |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* `block`
* `switch`
* 条件（三元）运算符
continue
========

**continue 声明**终止当前循环或标记循环的当前迭代中的语句执行，并在下一次迭代时继续执行循环。

尝试一下
----

语法
--
```

continue [ label ];
```


`label`

标识标号关联的语句

描述
--

与 `break` 语句的区别在于，continue 并不会终止循环的迭代，而是：

* 在 `while` 循环中，控制流跳转回条件判断；
* 在 `for` 循环中，控制流跳转到更新语句。

`continue` 语句可以包含一个可选的标号以控制程序跳转到指定循环的下一次迭代，而非当前循环。此时要求 `continue` 语句在对应的循环内部。

示例
--

### 在 `while` 语句中使用 `continue`

下述例子展示了一个在`i` 为 3 时执行`continue` 语句的 `while` 循环。因此，`n` 的值在几次迭代后分别为 1, 3, 7 和 12 ．


```js
i = 0;
n = 0;
while (i < 5) {
  i++;
  if (i === 3) {
    continue;
  }
  n += i;
}
```

### 使用带 label 的 continue

在下面的例子中，被标记为 `checkiandj` 的语句包含一个被标记为 `checkj` 的语句。当遇到`continue` 语句时，程序回到 `checkj` 语句的开始继续执行。每次遇到 `continue` 时，再次执行 `checkj` ，直到条件判断返回 false。之后完成 `checkiandj` 语句剩下的部分。

但如果 `continue` 的标号被改为 `checkiandj` ，那程序将会从 `checkiandj` 语句的开始继续运行。

参考 `label` 。


```js
var i = 0,
  j = 8;

checkiandj: while (i < 4) {
  console.log("i: " + i);
  i += 1;

  checkj: while (j > 4) {
    console.log("j: " + j);
    j -= 1;
    if (j % 2 == 0) continue checkj;
    console.log(j + " is odd.");
  }
  console.log("i = " + i);
  console.log("j = " + j);
}
```


输出：


```js
"i: 0";

// start checkj
"j: 8";
"7 is odd.";
"j: 7";
"j: 6";
"5 is odd.";
"j: 5";
// end checkj

"i = 1";
"j = 4";

"i: 1";
"i = 2";
"j = 4";

"i: 2";
"i = 3";
"j = 4";

"i: 3";
"i = 4";
"j = 4";
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-continue-statement |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* `break`
* `label`
return
======

**`return`** 语句终止函数的执行，并返回一个指定的值给函数调用者。

尝试一下
----

语法
--


```js
return [expression]
```


`expression`

要返回的值的表达式。如果忽略，则返回 `undefined`。

描述
--

当在函数体中使用 `return` 语句时，函数将会停止执行。如果指定一个值，则该值会被返回给函数调用者。例如，以下函数返回其参数 `x` 的平方，其中 `x` 是数字。


```js
function square(x) {
  return x \* x;
}
const demo = square(3);
// demo will equal 9
```


如果省略该值，则返回 `undefined`。

下面的 return 语句都会终止函数的执行：


```js
return;
return true;
return false;
return x;
return x + y / 3;
```

### 自动插入分号

自动插入分号（ASI）规则会影响 `return` 语句。在 `return` 关键字和被返回的表达式之间不允许使用换行符。


```js
return
a + b;
```


根据 ASI，被转换为：


```js
return;
a + b;
```


控制台会警告“unreachable code after return statement”。

**备注：** 从 Firefox 40 开始，如果在 `return` 语句后发现不可达的代码，控制台会显示一个警告。

为了避免这个问题（防止 ASI），你可以使用括号：


```js
return (
  a + b
);
```

示例
--

### 中断一个函数的执行

函数将会在 `return` 语句执行后立即中止。


```js
function counter() {
  for (let count = 1; ; count++) {
    // 无限循环
    console.log(`${count}A`); // 执行 5 次
    if (count === 5) {
      return;
    }
    console.log(`${count}B`); // 执行 4 次
  }
  console.log(`${count}C`); // 永远不会执行
}

counter();

// Output:
// 1A
// 1B
// 2A
// 2B
// 3A
// 3B
// 4A
// 4B
// 5A
```

### 返回一个函数

参见关于闭包的文章。


```js
function magic() {
  return function calc(x) {
    return x \* 42;
  };
}

const answer = magic();
answer(1337); // 56154
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-return-statement |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* 函数
* 闭包
with
====

**已弃用:** 不再推荐使用该特性。虽然一些浏览器仍然支持它，但也许已从相关的 web 标准中移除，也许正准备移除或出于兼容性而保留。请尽量不要使用该特性，并更新现有的代码；参见本页面底部的兼容性表格以指导你作出决定。请注意，该特性随时可能无法正常工作。

**备注：** 不建议使用 `with` 语句，因为它可能是混淆错误和兼容性问题的根源。有关详细信息，请参阅下面“描述”一节中的“语意不明的弊端”部分。

**`with`** 语句扩展一个语句的作用域链。

语法
--


```js
with (expression)
  statement
```


`expression`

将给定的表达式添加到在评估语句时使用的作用域链上。表达式周围的括号是必需的。

`statement`

任何语句。要执行多个语句，请使用一个块语句 (`{ ... }`) 对这些语句进行分组。

描述
--

JavaScript 查找某个未使用命名空间的变量时，会通过作用域链来查找，作用域链是跟执行代码的 context 或者包含这个变量的函数有关。'with'语句将某个对象添加到作用域链的顶部，如果在 statement 中有某个未使用命名空间的变量，跟作用域链中的某个属性同名，则这个变量将指向这个属性值。如果沒有同名的属性，则将拋出`ReferenceError`异常。

**备注：** 不推荐使用`with`，在 ECMAScript 5 严格模式中该标签已被禁止。推荐的替代方案是声明一个临时变量来承载你所需要的属性。

### 性能方面的利与弊

**利**：`with` 语句可以在不造成性能损失的情況下，减少变量的长度。其造成的附加计算量很少。使用 'with' 可以减少不必要的指针路径解析运算。需要注意的是，很多情況下，也可以不使用 with 语句，而是使用一个临时变量来保存指针，来达到同样的效果。

**弊**：`with` 语句使得程序在查找变量值时，都是先在指定的对象中查找。所以那些本来不是这个对象的属性的变量，查找起来将会很慢。如果是在对性能要求较高的场合，'with' 下面的 statement 语句中的变量，只应该包含这个指定对象的属性。

### 语义不明的弊端

**弊端**：`with` 语句使得代码不易阅读，同时使得 JavaScript 编译器难以在作用域链上查找某个变量，难以决定应该在哪个对象上来取值。请看下面的例子：


```js
function f(x, o) {
  with (o) print(x);
}
```


`f`被调用时，`x`有可能能取到值，也可能是`undefined`，如果能取到，有可能是在 o 上取的值，也可能是函数的第一个参数`x`的值（如果 o 中没有这个属性的话）。如果你忘记在作为第二个参数的对象 o 中定义`x`这个属性，程序并不会报错，只是取到另一个值而已。

**弊端**：使用 `with` 语句的代码，无法向前兼容，特別是在使用一些原生数据类型的时候。看下面的例子：


```js
function f(foo, values) {
  with (foo) {
    console.log(values);
  }
}
```


如果是在 ECMAScript 5 环境调用`f([1,2,3], obj)`，则`with`语句中变量`values`将指向函数的第二个参数`values`。但是，ECMAScript 6 标准给`Array.prototype`添加了一个新属性`values`，所有数组实例将继承这个属性。所以在 ECMAScript 6 环境中，`with`语句中变量`values`将指向`[1,2,3].values`。

示例
--

### 使用 with 语句

下面的`with`语句指定`Math`对象作为默认对象。`with`语句里面的变量，分別指向`Math`对象的`PI` 、`cos` 和 `sin` 函数，不用在前面添加命名空间。后续所有引用都指向`Math`对象。


```js
var a, x, y;
var r = 10;

with (Math) {
  a = PI \* r \* r;
  x = r \* cos(PI);
  y = r \* sin(PI / 2);
}
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-with-statement |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* `block`
* Strict mode (en-US)
* `Symbol.unscopables`
* `Array.prototype[@@unscopables]`
throw
=====

**`throw`** **语句**用来抛出一个用户自定义的异常。当前函数的执行将被停止（`throw` 之后的语句将不会执行），并且控制将被传递到调用堆栈中的第一个 `catch` 块。如果调用者函数中没有 `catch` 块，程序将会终止。

尝试一下
----

语法
--
```

throw expression;
```


`expression`

要抛出的表达式。

描述
--

使用`throw`语句来抛出一个异常。当你抛出异常时，`expression` 指定了异常的内容。下面的每行都抛出了一个异常：


```js
throw "Error2"; // 抛出了一个值为字符串的异常
throw 42; // 抛出了一个值为整数 42 的异常
throw true; // 抛出了一个值为 true 的异常
```


注意`throw`语句同样受到自动分号插入（ASI）机制的控制，在`throw`关键字和值之间不允许有行终止符。

示例
--

### 抛出一个对象

你可以在抛出异常时指定一个对象。然后可以在`catch`块中引用对象的属性。以下示例创建一个类型为`UserException`的对象，并在`throw`语句中使用它。


```js
function UserException(message) {
  this.message = message;
  this.name = "UserException";
}
function getMonthName(mo) {
  mo = mo - 1; // 调整月份数字到数组索引 (1=Jan, 12=Dec)
  var months = [
    "Jan",
    "Feb",
    "Mar",
    "Apr",
    "May",
    "Jun",
    "Jul",
    "Aug",
    "Sep",
    "Oct",
    "Nov",
    "Dec",
  ];
  if (months[mo] !== undefined) {
    return months[mo];
  } else {
    throw new UserException("InvalidMonthNo");
  }
}

try {
  // statements to try
  var myMonth = 15; // 15 超出边界并引发异常
  var monthName = getMonthName(myMonth);
} catch (e) {
  var monthName = "unknown";
  console.log(e.message, e.name); // 传递异常对象到错误处理
}
```

### 另一个抛出异常对象的示例

下面的示例中测试一个字符串是否是美国邮政编码。如果邮政编码是无效的，那么`throw`语句将会抛出一个类型为 `ZipCodeFormatException`的异常对象实例。


```js
/\*
 \* 创建 ZipCode 示例。
 \*
 \* 可被接受的邮政编码格式：
 \* 12345
 \* 12345-6789
 \* 123456789
 \* 12345 6789
 \*
 \* 如果构造函数参数传入的格式不符合以上任何一个格式，将会抛出异常。
 \*/

function ZipCode(zip) {
  zip = new String(zip);
  pattern = /[0-9]{5}([- ]?[0-9]{4})?/;
  if (pattern.test(zip)) {
    // zip code value will be the first match in the string
    this.value = zip.match(pattern)[0];
    this.valueOf = function () {
      return this.value;
    };
    this.toString = function () {
      return String(this.value);
    };
  } else {
    throw new ZipCodeFormatException(zip);
  }
}

function ZipCodeFormatException(value) {
  this.value = value;
  this.message = "不是正确的邮政编码";
  this.toString = function () {
    return this.value + this.message;
  };
}

/\*
 \* 这可能是一个验证美国地区中的脚本
 \*/

const ZIPCODE\_INVALID = -1;
const ZIPCODE\_UNKNOWN\_ERROR = -2;

function verifyZipCode(z) {
  try {
    z = new ZipCode(z);
  } catch (e) {
    if (e instanceof ZipCodeFormatException) {
      return ZIPCODE\_INVALID;
    } else {
      return ZIPCODE\_UNKNOWN\_ERROR;
    }
  }
  return z;
}

a = verifyZipCode(95060); // 返回 95060
b = verifyZipCode(9560); // 返回 -1
c = verifyZipCode("a"); // 返回 -1
d = verifyZipCode("95060"); // 返回 95060
e = verifyZipCode("95060 1234"); // 返回 95060 1234
```

### 重新抛出异常

你可以使用`throw`来抛出异常。下面的例子捕捉了一个异常值为数字的异常，并在其值大于 50 后重新抛出异常。重新抛出的异常传播到闭包函数或顶层，以便用户看到它。


```js
try {
  throw n; // 抛出一个数值异常
} catch (e) {
  if (e <= 50) {
    // 异常在 1-50 之间时，直接处理
  } else {
    // 异常无法处理，重新抛出
    throw e;
  }
}
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-throw-statement |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* `try...catch`
* `Error`
表达式语句
=====

**表达式语句**是指在需要语句的地方使用的表达式。该表达式被执行后，它的结果将被丢弃——因此，它仅对有着副作用的表达式有意义，例如执行函数或者更新变量。

语法
--


```js
expression;
```


`expression`

要计算的任意表达式。有些表达式可能与其他语句产生歧义，因此被禁用。

描述
--

除了专用的语句语法外，你也可以将几乎任何表达式用作单独的语句。表达式语句语法需要在表达式的结尾添加一个分号，但是如果缺少分号导致语法无效，自动分号补全的过程可能会为你插入一个分号。

因为表达式执行之后就会被丢弃，表达式的结果不再可用。因此，表达式必须有一些副作用才能有用。表达式语句通常是：

* 函数调用（`console.log("Hello");`、`[1, 2, 3].forEach((i) => console.log(i));`）
* 带标签的模版字符串
* 赋值表达式，包括复合赋值
* 自增和自减
* `delete`
* `import()` (en-US)
* `yield` 和 `yield*`

如果表达式调用 getter 或者触发强制类型转换，它们也可能有副作用。

### 被禁用的表达式

为了将表达式用作语句，它禁止与其他的语句语法有歧义。因此，表达式禁止以以下任何标记开头：

* `function`：这将是 `function` 声明或者 `function*` 声明，而不是 `function` 表达式或者 `function*` 表达式
* `async function`：这将是 `async function` 声明或者 `async function*` 声明，而不是 `async function` 表达式或者 `async function*` 表达式
* `class`：这将是 `class` 声明，而不是 `class` 表达式
* `let[`：这将是带有数组解构的 `let` 声明，而不是称为 `let` 变量的属性访问器（`let` 仅可以是在非严格模式下的标识符）
* `{`：这将是一个块语句，而不是对象字面量

因此，以下所有内容均无效：


```js
function foo() {
  console.log("foo");
}(); // SyntaxError: Unexpected token '('

// 出于某种原因，你有一个叫做 `let` 的变量
var let = [1, 2, 3];
let[0] = 4; // SyntaxError: Invalid destructuring assignment target

{
  foo: 1,
  bar: 2, // SyntaxError: Unexpected token ':'
};
```


更危险的是，有时候代码碰巧是有效的语法，但是这并不是你想要的。


```js
// 出于某种原因，你有一个叫做 `let` 的变量
var let = [1, 2, 3];

function setIndex(index, value) {
  if (index >= 0) {
    // 打算分配给数组 `let`，但是却创建一个额外的变量！
    let[index] = value;
  }
}

setIndex(0, [1, 2]);
console.log(let); // [1, 2, 3]

// 这并不是一个对象字面量，而是一个块语句。
// 其中 `foo` 是标签，`1` 是表达式语句。
// 这通常在控制台中发生
{ foo: 1 };
```


为了避免这些问题，你可以使用圆括号，使语句明确地作为一个表达式。


```js
(function foo() {
  console.log("foo");
})();
```

示例
--

### 避免控制流语句

你可以使用表达式语句来避免几乎所有控制流语句的使用。例如，可以使用三元运算符和逻辑运算符替换 `if...else`。像 `for` 或者 `for...of` 可以使用数组方法来替换。


```js
// 使用控制流语句
function range(start, end) {
  if (start > end) {
    [start, end] = [end, start];
  }
  const result = [];
  for (let i = start; i < end; i++) {
    result.push(i);
  }
  return result;
}

// 使用表达式语句
function range2(start, end) {
  start > end && ([start, end] = [end, start]);
  return Array.from({ length: end - start }, (\_, i) => start + i);
}
```


**警告：** 这仅演示了该语言的功能。过度的使用表达式语句来替代控制流语句会大大降低代码的可读性。

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-expression-statement |

参见
--

* 语句和声明
* 表达式和运算符
for await...of
==============

**`for await...of` 语句**创建一个循环，该循环遍历异步可迭代对象以及同步可迭代对象，包括：内置的 `String`, `Array`，类似数组对象 (例如 `arguments` 或 `NodeList`)，`TypedArray`, `Map`, `Set` 和用户定义的异步/同步迭代器。它使用对象的每个不同属性的值调用要执行的语句来调用自定义迭代钩子。

类似于 `await` 运算符一样，该语句只能在一个async function 内部使用。

**备注：** `for await...of` 不适用于不是异步可迭代的异步迭代器。

语法
--
```

for await (variable of iterable) {
  statement
}
```


`variable`

在每次迭代中，将不同属性的值分配给变量。变量有可能以`const`, `let`, 或者 `var`来声明。

`iterable`

被迭代枚举其属性的对象。与 for...of 相比，这里的对象可以返回 `Promise`，如果是这样，那么 `variable` 将是 `Promise` 所包含的值，否则是值本身。

示例
--

### 迭代异步可迭代对象

你还可以迭代一个明确实现异步迭代协议的对象：


```js
var asyncIterable = {
  [Symbol.asyncIterator]() {
    return {
      i: 0,
      next() {
        if (this.i < 3) {
          return Promise.resolve({ value: this.i++, done: false });
        }

        return Promise.resolve({ done: true });
      },
    };
  },
};

(async function () {
  for await (num of asyncIterable) {
    console.log(num);
  }
})();

// 0
// 1
// 2
```

### 迭代异步生成器

异步生成器已经实现了异步迭代器协议，所以可以用 `for await...of`循环。


```js
async function\* asyncGenerator() {
  var i = 0;
  while (i < 3) {
    yield i++;
  }
}

(async function () {
  for await (num of asyncGenerator()) {
    console.log(num);
  }
})();
// 0
// 1
// 2
```


有关使用`for await... of`考虑迭代 API 中获取数据的异步 generator 更具体的例子。这个例子首先为一个数据流创建了一个异步 generator，然后使用它来获得这个 API 的响应值的大小。


```js
async function\* streamAsyncIterator(stream) {
  const reader = stream.getReader();
  try {
    while (true) {
      const { done, value } = await reader.read();
      if (done) {
        return;
      }
      yield value;
    }
  } finally {
    reader.releaseLock();
  }
}
// 从 url 获取数据并使用异步 generator 来计算响应值的大小
async function getResponseSize(url) {
  const response = await fetch(url);
  // Will hold the size of the response, in bytes.
  let responseSize = 0;
  // 使用 for-await-of 循环。异步 generator 会遍历响应值的每一部分
  for await (const chunk of streamAsyncIterator(response.body)) {
    // Incrementing the total response length.
    responseSize += chunk.length;
  }

  console.log(`Response Size: ${responseSize} bytes`);
  // expected output: "Response Size: 1071472"
  return responseSize;
}
getResponseSize("https://jsonplaceholder.typicode.com/photos");
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-for-in-and-for-of-statements |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* `Symbol.asyncIterator`
* `Statements/for...of`
while
=====

**while 语句**可以在某个条件表达式为真的前提下，循环执行指定的一段代码，直到那个表达式不为真时结束循环。

尝试一下
----

语法
--
```

while (condition)
  statement
```


`condition`

条件表达式，在每次循环前被求值。如果求值为真，`statement`就会被执行。如果求值为假，则跳出`while`循环执行后面的语句。

`statement`

只要条件表达式求值为真，该语句就会一直被执行。要在循环中执行多条语句，可以使用块语句（`{ ... }`）包住多条语句。注意：使用`break`语句在`condition`计算结果为真之前停止循环。

示例
--

下面的 `while` 循环会一直循环若干次，直到 `n` 等于 `3`。


```js
var n = 0;
var x = 0;

while (n < 3) {
  n++;
  x += n;
}
```


在每次循环中，`n` 都会自增 `1`，然后再把 `n` 加到 `x` 上。因此，在每轮循环结束后，`x` 和 `n` 的值分别是：

* 第一轮后：`n` = 1，`x` = 1
* 第二轮后：`n` = 2，`x` = 3
* 第三轮后：`n` = 3，`x` = 6

当完成第三轮循环后，条件表达式`n`< 3 不再为真，因此循环终止。

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-while-statement |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* `do...while`
* `for`
break
=====

**break 语句**中止当前循环，`switch`语句或`label` 语句，并把程序控制流转到紧接着被中止语句后面的语句。

语法
--
```

break [label];
```


`label` 可选

与语句标签相关联的标识符。如果 break 语句不在一个循环或 `switch` 语句中，则该项是必须的。

描述
--

`break`语句包含一个可选的标签，可允许程序摆脱一个被标记的语句。`break`语句需要内嵌在引用的标签中。被标记的语句可以是任何 `块`语句；不一定是循环语句。

break 语句不能在 function 函数体中直接使用，break 语句应嵌套在要中断的当前循环、switch 或 label 语句中。

示例
--

### break in while loop

下面的函数里有个 `break` 语句，当 `i` 为 3 时，会中止 `while` 循环，然后返回 3 \* `x` 的值。


```js
function testBreak(x) {
  var i = 0;

  while (i < 6) {
    if (i == 3) {
      break;
    }
    i += 1;
  }

  return i \* x;
}
```

### break in switch statements

在下面的代码中， `break` 使用在 `switch` 语句中，当遇到匹配到 case 后，就会执行相应的代码并中断循环体。
```

const food = "sushi";

switch (food) {
  case "sushi":
    console.log("Sushi is originally from Japan.");
    break;
  case "pizza":
    console.log("Pizza is originally from Italy.");
    break;
  default:
    console.log("I have never heard of that dish.");
    break;
}
```

### break in labeled blocks

下面的代码中一起使用 `break` 语句和被标记的块语句。一个 `break` 语句必须内嵌在它引用的标记中。注意，`inner_block` 内嵌在 `outer_block` 中。


```js
outer\_block: {
  inner\_block: {
    console.log("1");
    break outer_block; // breaks out of both inner\_block and outer\_block
    console.log(":-("); // skipped
  }

  console.log("2"); // skipped
}
```

### break in labeled blocks that throw

下面的代码同样使用了 `break` 语句和被标记的块语句，但是产生了一个语法错误，因为它的 `break` 语句在 `block_1` 中，但是引用了 `block_2`。`break` 语句必须内嵌在它引用的标签中。


```js
block\_1:{
  console.log ('1');
  break block_2;            // SyntaxError: label not found
}

block\_2:{
  console.log ('2');
}
```

### break within functions

在下面的代码同样会产生 SyntaxError，因为它并没被正确的使用在循环、switch 或 label 语句中。
```

function testBreak(x) {
  var i = 0;

  while (i < 6) {
    if (i == 3) {
      (function() {
        break;
      })();
    }
    i += 1;
  }

return i * x;
}

testBreak(1); // SyntaxError: Illegal break statement
```


```
block_1: {
  console.log('1');
  ( function() {
    break block_1; // SyntaxError: Undefined label 'block_1'
  })();
}
```

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-break-statement |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* `continue`
* label
* `switch`