Skip to content

语句

1. 表达式语句

  • 最简单的一种语句就是有副效应的表达式。
  • 赋值语句是一种主要的表达式语句。

2. 复合语句与空语句

通过语句块(代码块)可以将多个语句组合为一个复合语句:

javascript
{
  x = Math.PI;
  cx = Math.cos(x);
  console.log("cos(n) = " + cx);  
}

复合语句允许在 JavaScript 语法期待一个语句时使用多个语句。空语句正好相反,表示不包含任何语句:

javascript
; // 空语句

空语句偶尔有用,如创建空循环体的循环:

javascript
// 初始化数组a
for (let i = 0; i < a.length; a[i++]=0);

3. 条件语句

条件语句也称为分支语句。

3.1 if

if 条件后就算只有一行语句,也建议使用代码块包裹。

3.2 else-if

用于根据条件执行多段代码中的一段:

javascript
if (n === 1) {
  
} else if (n === 2) {
  
} else if (n === 3) {
  
} else {
  
}

3.3 switch

switch 关键字后跟一个带括号的表达式和代码块,执行时,会计算表达式的值,然后对比 case 标签,相等(===)则执行对于代码块。如果没有找到相等的值,则找 default 标签,如果没 default ,则跳过整个代码块。

javascript
switch(n) {
  case 1:
    // 执行第一个代码块

    break;
  case 2:
    // 第二个

    break;
  case 3:
    break;
  default: 
    break;
}

注意

  • 如果 case 后的代码块中没 break 语句,则会继续执行下一个 case
  • 在函数中使用 switch 时可以用 return 替换 break,后续代码不会执行。
  • case 后可跟任意代码块,通过全等 ===switch 表达式值进行匹配。

4. 循环语句

4.1 while

javascript
while (expression) {
  statement
}

4.2 do-while

while 的区别:

  • do while 循环体至少会执行一次。
  • do 循环必须以分号结束,而 while 循环体使用花括号时不需要分号。
javascript
let len = a.length, i = 0;
if (len === 0) {
  console.log("Empty Array")
} else {
  do {
    console.log(a[i])
  } while (++i < len); // 必须跟分号
}

4.3 for

javascript
for (initialize; test; increment) {
  statement
}
  • initialize、test、increment 分别代表初始化、测试和递增三个表达式,初始化只执行一次。
  • 三个表达式中任何一个都可以省略,只有两个分号是必需的。
  • for(;;)while(true) 一样,是无限循环。

4.4 for/of

for/of 循环专门用于可迭代对象,如数组、字符串、集合和映射。

javascript
let data = [1, 2, 3, 4, 5], sum = 0;
for (let element of data) {
  sum += element;
}
sum // 15

对数组使用 for/of 迭代是实时的,在循环体内改变数组会影响循环结果,如循环体内想数组添加元素,则会造成无限循环。

4.4.1 for/of 与对象

  • 对象默认不可迭代,对常规对象使用 for/of 会报错。
  • 如果想迭代对象属性,可使用 for/inObject.keys() 方法,该方法会返回对象属性数组。
  • Object.values() 会返回对象的属性值构成的数组,Object.entries() 返回数组构成的数组,每个数组元素是对象键值对构成的数组。
javascript
let pairs = "";
for (let [k, v] of Object.entries(o)) {
  pairs += k + v
}

4.4.2 for/of 与字符串

字符串按照码点进行迭代,而不是 UTF-16 字符(码元),有的字符可能长度为 2,占据两个码元,但只遍历一次。

4.4.3 for/of 与 Set 和 Map

  • for/of 迭代 Set 时,会把所有元素遍历一遍。
  • for/of 迭代 Map 时,迭代的是键值对数组,类似于迭代 Object.entries()
javascript
let m = new Map([[1, "one"]])
for (let [k, v] of m) {
  key // 1
  value // "one"
}

4.4.4 for/await 与异步迭代

ES2018 新增的一种 for/of 循环,需使用异步迭代器:

javascript
// 从异步可迭代流中读取数据块并打印
async function printStream(stream) {
  for await (let chunk of stream) {
   console.log(chunk); 
  }
}

4.5 for/in

  • for/in 循环后面可以是任意对象,for/of 只能是可迭代对象。
  • for/in 是一开始就有的,for/of 是 ES6 新增的。
  • for/in 用于遍历对象属性,但不会遍历所有属性,比如名为 Symbol 的属性,只能遍历可枚举的属性。JavaScript 核心定义的内部方法是不能枚举的,如 toString()
  • 默认情况下,手写代码定义的所有属性和方法都是可枚举的。

5. 语句

5.1 语句标签

通过前置一个标识符和冒号,可以给任何语句加标签:identifier: statement

一般也就是给循环语句加标签,然后用 breakcontinue 进行跳转:

javascript
mainloop: while(token !== null) {
  ...
  continue mainloop; // 跳到命名循环的下一次迭代
}

注意

  • 如果两条语句有嵌套关系,则不能使用相同的标签。
  • breakcontinue 是JavaScript 中唯一使用语句标签的语句。

5.2 break

  • break 单独使用时,会导致循环或 switch 语句立即退出。
  • break 后可跟标签,会跳转到指定标签语句的末尾或终止该语句。如果想中断一个并非最接近的嵌套循环或 switch 语句,就要使用带标签的 break 语句。
javascript
let matrix = getData()
let sum = 0, success = false;
computeSum: if (matrix) {
  for (let x = 0; x < matrix.length; x++) {
    let row = matrix[x];
    if (!row) break computeSum;
    for (let y = 0; y < row.length; y++) {
      let cell = row[y];
      if (isNaN(cell)) break computeSum;
      sum += cell;
    }
  }
  success = true;
}
// 如果 success 为 false,表明矩阵有非法值,否则,计算矩阵元素和

5.3 continue

continue 语句与 break 类似,但 continue 不会退出循环,而是跳过当前循环,从头开始执行循环的下一次迭代。

注意

  • 无论带不带标签,continue 都只能在循环体内使用。
  • continue 带标签,标签只能用于循环语句,否则会报错。

5.4 return

  • return 语句只能出现在函数体内,否则会报错。
  • 函数体内没有 return,返回 undefined
  • 不能在 return 和返回值之间插入换行。

5.5 yield

yield 语句非常类似 return,但只能用在生成器函数中,以回送生成的值序列的下一个值。

javascript
function* range(from, to) {
  for (let i = from; i <= to; i++) {
    yield i;
  }
}

5.6 throw

  • 在 JavaScript 中,每当运行时发生错误或程序里使用 throw 语句时都会抛出异常,可以使用 try/catch/finally 语句捕获异常。
  • 语法:throw expression,其中 expression 可以是任何值,如表示错误码的数值,或者可读的错误消息字符串。
  • JavaScript 解释器在抛出错误时会使用 Error 类及其字类,在自己代码中也可以使用这些类。Error 对象有一个 name 属性和一个 message 属性,分别用于指定错误类型和保存传入构造函数的字符串。
javascript
function factorial(x) {
  if (x < 0) throw new Error('x必须大于0');
  let f;
  for (f = 1; x > 1; f *= x, x--);
  return f;
}

注意

  • 抛出异常时,JavaScript 程序会立即停止程序的执行并跳到最近的异常处理程序。
  • 异常是沿着方法的词法结构和调用栈向上传播的,如果没找到任何异常调用程序,则将异常作为错误报告给用户。

5.7 try/catch/finally

  • try/catch/finally 语句是 JavaScript 中的异常处理机制,try 用于定义要处理异常的代码块,catch 在发生异常时被调用,finally 无论是否发生异常,一定会执行,通常用于执行清理。
  • catchfinally 是可选的,但只要有 try,则必须有二者中的一个。
  • catch 后通常会跟一个包含在圆括号中的标识符,类似函数参数,当捕获到异常时,与异常关联的值会赋值给这个参数。该参数具有块作用域,即只在 catch 块中有用。
  • 如果由于 returncontinuebreak 等跳转语句离开了 try 块,在跳转之前会执行 finally 块。
  • 如果 finally 子句抛出异常,该异常会代替正被抛出的其它异常;如果执行了 return 语句,则相应方法正常返回,即使有正在抛出且尚未处理的异常。
javascript
try {
  let n = Number(prompt("请输入一个正整数", ""));
  let f = factorial(n);
  alert(n + "!=" + f);
} catch (e) {
  alert(e)
}

6. 其它语句

6.1 with

  • 语法:with(object) statement。这个语句创建了一个临时作用域,以 object 对象的属性作为变量,然后在该作用域中执行代码。
  • 使用 with 语句主要是为了更方便的使用深度嵌套对象:
javascript
document.form[0].address.value = ''
// 通过 with 简写
with(document.form[0]) {
  address.value = ''
}

注意

严格模式下禁止使用 with,非严格模式也不应该使用,因为会造成代码难以优化。

6.2 debugger

用于调试,类似于断点,如果使用浏览器并打开了开发者控制台,这个语句就会导致断点。

6.3 "use strict"

  • "use strict" 指令用于开启严格模式,不是语句,只能出现在脚本或函数体的开头。
  • 除了显式声明严格模式,任何位于 class 体或 ES6 模块中的代码全部默认为严格代码。

严格模式与非严格模式的区别

  • 严格模式下不允许使用 with 语句。
  • 严格模式下,所有变量都必须声明。
  • 严格模式下,函数如果作为函数被调用(而不是方法),其 this 值为 undefined(非严格模式下为全局对象)。
  • 等等。

7. 声明

7.1 const、let 和 var

ES6 之后使用 const 声明常量 let 声明变量,ES6 之前只能使用 var 声明变量,不能声明常量。

7.2 function

function 声明用于定义函数:

javascript
function area(radius) {
  return Math.PI * radius * radius;
}
  • 无论在作用域中什么地方声明函数都会被“提升”,因此调用函数的代码可能位于声明函数的代码之前。
  • 生成器声明使用 function 关键字后跟一个星号。

7.3 class

ES6 之后,可以用 class 创建类,与函数不同,类声明不会提升,因此不能在还没声明类时就先使用类。

javascript
class Circle {
  constructor(radius) {
    this.r = radius;
  }

  area() {
    return Math.PI * this.r * this.r;
  }
}

7.4 import 和 export

  • JavaScript 中一个代码文件就是一个模块,有自己的全局作用域(模块作用域),完全与其它模块无关。
  • import 指令用于从其它模块中导入一个或多个值,并为这些值指定名字。
javascript
import Circle from './circle.js'
import { PI, TAU } from './constants.js'
import { magnitude as hypotenuse } from './utils.js'
  • export 指令用于把当前一个或多个值导出,导出后其它模块才能导入这些值。
javascript
const PI = Math.PI;
const TAU = 2 * PI;
export {
  PI,
  TAU
}
  • export 关键字也可用作其它声明的标识符,构成复合声明,在定义变量、常量、函数或类的同时导出它们。
javascript
export const TAU = 2 * PI;
export function magnitude(x, y) {
  return Math.sqrt(x * x + y * y);
}
  • 如果一个模块只导出一个值,通常会使用特殊的 export default 形式。
javascript
export default class Circle {
  
}