控制流程和错误处理

JavaScript supports a compact set of statements, specifically control flow statements, that you can use to incorporate a great deal of interactivity in your application. This chapter provides an overview of these statements.

JavaScript 参考 contains exhaustive details about the statements in this chapter. The semicolon ( ; ) character is used to separate statements in JavaScript code.

Any JavaScript expression is also a statement. See 表达式和运算符 for complete information about expressions.

Block statement

The most basic statement is a block statement , which is used to group statements. The block is delimited by a pair of curly brackets:

{
  statement_1;
  statement_2;
  ⋮
  statement_n;
}
				

范例

Block statements are commonly used with control flow statements ( if , for , while ).

while (x < 10) {
  x++;
}
				

Here, { x++; } is the block statement.

Important : JavaScript before ECMAScript2015 (6 th edition) does not have block scope!  In older JavaScript, variables introduced within a block are scoped to the containing function or script, and the effects of setting them persist beyond the block itself. In other words, block statements do not define a scope .

"Standalone" blocks in JavaScript can produce completely different results from what they would produce in C or Java. For example:

var x = 1;
{
  var x = 2;
}
console.log(x); // outputs 2
					

This outputs 2 because the var x statement within the block is in the same scope as the var x statement before the block. (In C or Java, the equivalent code would have outputted 1 .)

Since ECMAScript2015 let and const variable declarations are block-scoped. See the let and const reference pages for more information.

Conditional statements

A conditional statement is a set of commands that executes if a specified condition is true. JavaScript supports two conditional statements: if...else and switch .

if...else statement

使用 if statement to execute a statement if a logical condition is true . Use the optional else clause to execute a statement if the condition is false .

An if statement looks like this:

if (condition) {
  statement_1;
} else {
  statement_2;
}
				

在这里, condition can be any expression that evaluates to true or false . (See Boolean for an explanation of what evaluates to true and false .)

condition evaluates to true , statement_1 is executed. Otherwise, statement_2 is executed. statement_1 and statement_2 can be any statement, including further nested if statements.

You can also compound the statements using else if to have multiple conditions tested in sequence, as follows:

if (condition_1) {
  statement_1;
} else if (condition_2) {
  statement_2;
} else if (condition_n) {
  statement_n;
} else {
  statement_last;
}
				

In the case of multiple conditions, only the first logical condition which evaluates to true will be executed. To execute multiple statements, group them within a block statement ( { … } ).

Best practice

In general, it's good practice to always use block statements— especially when nesting if statements:

if (condition) {
  statement_1_runs_if_condition_is_true;
  statement_2_runs_if_condition_is_true;
} else {
  statement_3_runs_if_condition_is_false;
  statement_4_runs_if_condition_is_false;
}
				

It's unwise to use simple assignments in a conditional expression, because the assignment can be confused with equality when glancing over the code.

For example, do not write code like this:

// Prone to being misread as "x == y"
if (x = y) {
  /* statements here */
}
				

If you need to use an assignment in a conditional expression, a common practice is to put additional parentheses around the assignment, like this:

if ((x = y)) {
  /* statements here */
}
				

Falsy values

The following values evaluate to false (also known as Falsy values):

All other values—including all objects—evaluate to true when passed to a conditional statement.

Caution: Do not confuse the primitive boolean values true and false with the true and false values of the Boolean object!

例如:

var b = new Boolean(false);
if (b)         // this condition evaluates to true
if (b == true) // this condition evaluates to false
					

范例

In the following example, the function checkData 返回 true if the number of characters in a Text object is three. Otherwise, it displays an alert and returns false .

function checkData() {
  if (document.form1.threeChar.value.length == 3) {
    return true;
  } else {
    alert(
        'Enter exactly three characters. ' +
        `${document.form1.threeChar.value} is not valid.`);
    return false;
  }
}
				

switch statement

A switch statement allows a program to evaluate an expression and attempt to match the expression's value to a case label. If a match is found, the program executes the associated statement.

A switch statement looks like this:

switch (expression) {
  case label_1:
    statements_1
    [break;]
  case label_2:
    statements_2
    [break;]
    …
  default:
    statements_def
    [break;]
}
				

JavaScript evaluates the above switch statement as follows:

break statements

可选 break statement associated with each case clause ensures that the program breaks out of switch once the matched statement is executed, and then continues execution at the statement following switch 。若 break is omitted, the program continues execution inside the switch statement (and will evaluate the next case , and so on).

范例

In the following example, if fruittype evaluates to 'Bananas' , the program matches the value with case 'Bananas' and executes the associated statement. When break is encountered, the program exits the switch and continues execution from the statement following switch 。若 break were omitted, the statement for case 'Cherries' would also be executed.

switch (fruittype) {
  case 'Oranges':
    console.log('Oranges are $0.59 a pound.');
    break;
  case 'Apples':
    console.log('Apples are $0.32 a pound.');
    break;
  case 'Bananas':
    console.log('Bananas are $0.48 a pound.');
    break;
  case 'Cherries':
    console.log('Cherries are $3.00 a pound.');
    break;
  case 'Mangoes':
    console.log('Mangoes are $0.56 a pound.');
    break;
  case 'Papayas':
    console.log('Mangoes and papayas are $2.79 a pound.');
    break;
  default:
   console.log(`Sorry, we are out of ${fruittype}.`);
}
console.log("Is there anything else you'd like?");
				

Exception handling statements

You can throw exceptions using the throw statement and handle them using the try...catch statements.

Exception types

Just about any object can be thrown in JavaScript. Nevertheless, not all thrown objects are created equal. While it is common to throw numbers or strings as errors, it is frequently more effective to use one of the exception types specifically created for this purpose:

throw statement

使用 throw statement to throw an exception. A throw statement specifies the value to be thrown:

throw expression;
				

You may throw any expression, not just expressions of a specific type. The following code throws several exceptions of varying types:

throw 'Error2';   // String type
throw 42;         // Number type
throw true;       // Boolean type
throw {toString: function() { return "I'm an object!"; } };
				

注意: You can specify an object when you throw an exception. You can then reference the object's properties in the catch 块。

// Create an object type UserException
function UserException(message) {
  this.message = message;
  this.name = 'UserException';
}
// Make the exception convert to a pretty string when used as a string
// (e.g., by the error console)
UserException.prototype.toString = function() {
  return `${this.name}: "${this.message}"`;
}
// Create an instance of the object type and throw it
throw new UserException('Value too high');
				

try...catch statement

try...catch statement marks a block of statements to try, and specifies one or more responses should an exception be thrown. If an exception is thrown, the try...catch statement catches it.

try...catch statement consists of a try block, which contains one or more statements, and a catch block, containing statements that specify what to do if an exception is thrown in the try 块。

In other words, you want the try block to succeed—but if it does not, you want control to pass to the catch block. If any statement within the try block (or in a function called from within the try block) throws an exception, control immediately shifts to the catch block. If no exception is thrown in the try block, the catch block is skipped. The finally block executes after the try and catch blocks execute but before the statements following the try...catch 语句。

The following example uses a try...catch statement. The example calls a function that retrieves a month name from an array based on the value passed to the function. If the value does not correspond to a month number ( 1 12 ), an exception is thrown with the value "InvalidMonthNo" and the statements in the catch block set the monthName variable to 'unknown' .

function getMonthName(mo) {
  mo = mo - 1; // Adjust month number for array index (1 = Jan, 12 = Dec)
  let months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul',
                'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
  if (months[mo]) {
    return months[mo];
  } else {
    throw 'InvalidMonthNo'; // throw keyword is used here
  }
}
try { // statements to try
  monthName = getMonthName(myMonth); // function could throw exception
}
catch (e) {
  monthName = 'unknown';
  logMyErrors(e); // pass exception object to error handler (i.e. your own function)
}
				

catch block

You can use a catch block to handle all exceptions that may be generated in the try 块。

catch (catchID) {
  statements
}
				

catch block specifies an identifier ( catchID in the preceding syntax) that holds the value specified by the throw statement. You can use this identifier to get information about the exception that was thrown.

JavaScript creates this identifier when the catch block is entered. The identifier lasts only for the duration of the catch block. Once the catch block finishes executing, the identifier no longer exists.

For example, the following code throws an exception. When the exception occurs, control transfers to the catch 块。

try {
  throw 'myException'; // generates an exception
}
catch (err) {
  // statements to handle any exceptions
  logMyErrors(err);    // pass exception object to error handler
}
				

Best practice: When logging errors to the console inside a catch block, using console.error() 而不是 console.log() is advised for debugging. It formats the message as an error, and adds it to the list of error messages generated by the page.

finally block

finally block contains statements to be executed after the try and catch blocks execute. Additionally, the finally block executes before the code that follows the try…catch…finally 语句。

It is also important to note that the finally block will execute whether or not an exception is thrown. If an exception is thrown, however, the statements in the finally block execute even if no catch block handles the exception that was thrown.

可以使用 finally block to make your script fail gracefully when an exception occurs. For example, you may need to release a resource that your script has tied up.

The following example opens a file and then executes statements that use the file. (Server-side JavaScript allows you to access files.) If an exception is thrown while the file is open, the finally block closes the file before the script fails. Using finally here ensures that the file is never left open, even if an error occurs.

openMyFile();
try {
  writeMyFile(theData); // This may throw an error
} catch(e) {
  handleError(e); // If an error occurred, handle it
} finally {
  closeMyFile(); // Always close the resource
}
				

finally block returns a value, this value becomes the return value of the entire try…catch…finally production, regardless of any return statements in the try and catch blocks:

function f() {
  try {
    console.log(0);
    throw 'bogus';
  } catch(e) {
    console.log(1);
    return true;    // this return statement is suspended
                    // until finally block has completed
    console.log(2); // not reachable
  } finally {
    console.log(3);
    return false;   // overwrites the previous "return"
    console.log(4); // not reachable
  }
  // "return false" is executed now
  console.log(5);   // not reachable
}
console.log(f()); // 0, 1, 3, false
				

Overwriting of return values by the finally block also applies to exceptions thrown or re-thrown inside of the catch block:

function f() {
  try {
    throw 'bogus';
  } catch(e) {
    console.log('caught inner "bogus"');
    throw e; // this throw statement is suspended until
             // finally block has completed
  } finally {
    return false; // overwrites the previous "throw"
  }
  // "return false" is executed now
}
try {
  console.log(f());
} catch(e) {
  // this is never reached!
  // while f() executes, the `finally` block returns false,
  // which overwrites the `throw` inside the above `catch`
  console.log('caught outer "bogus"');
}
// OUTPUT
// caught inner "bogus"
// false
				

Nesting try...catch statements

You can nest one or more try...catch statements.

If an inner try...catch statement does not have a catch block:

  1. it must contain a finally block, and
  2. the enclosing try...catch statement's catch block is checked for a match.

更多信息,见 nested try-blocks on the try...catch reference page.

Utilizing Error objects

Depending on the type of error, you may be able to use the name and message properties to get a more refined message.

name property provides the general class of Error (譬如 DOMException or Error ), while message generally provides a more succinct message than one would get by converting the error object to a string.

If you are throwing your own exceptions, in order to take advantage of these properties (such as if your catch block doesn't discriminate between your own exceptions and system ones), you can use the Error 构造函数。

例如:

function doSomethingErrorProne() {
  if (ourCodeMakesAMistake()) {
    throw (new Error('The message'));
  } else {
    doSomethingToGetAJavascriptError();
  }
}
⋮
try {
  doSomethingErrorProne();
} catch (e) {               // NOW, we actually use `console.error()`
  console.error(e.name);    // logs 'Error'
  console.error(e.message); // logs 'The message', or a JavaScript error message
}
				
  1. JavaScript
  2. 教程:
  3. 完整初学者
    1. JavaScript 基础
    2. JavaScript 第一步
    3. JavaScript 构建块
    4. 引入 JavaScript 对象
  4. JavaScript 指南
    1. 介绍
    2. 语法和类型
    3. 控制流程和错误处理
    4. 循环和迭代
    5. 函数
    6. 表达式和运算符
    7. 数字和日期
    8. 文本格式
    9. 正则表达式
    10. Indexed collections
    11. Keyed collections
    12. Working with objects
    13. 对象模型的细节
    14. Using promises
    15. 迭代器和生成器
    16. Meta programming
    17. JavaScript 模块
  5. 中间体
    1. 引入 JavaScript 对象
    2. 客户端侧 Web API
    3. 重新介绍 JavaScript
    4. JavaScript 数据结构
    5. 相等比较和相同
    6. 闭包
  6. 高级
    1. 继承和原型链
    2. 严格模式
    3. JavaScript 类型数组
    4. 内存管理
    5. 并发模型和事件循环
  7. 参考:
  8. 内置对象
    1. AggregateError
    2. Array
    3. ArrayBuffer
    4. AsyncFunction
    5. AsyncIterator
    6. Atomics
    7. BigInt
    8. BigInt64Array
    9. BigUint64Array
    10. Boolean
    11. DataView
    12. Date
    13. Error
    14. EvalError
    15. Float32Array
    16. Float64Array
    17. Function
    18. Generator
    19. GeneratorFunction
    20. Infinity
    21. Int16Array
    22. Int32Array
    23. Int8Array
    24. InternalError
    25. Intl
    26. Intl.Collator
    27. Intl.DateTimeFormat
    28. Intl.DisplayNames
    29. Intl.ListFormat
    30. Intl.Locale
    31. Intl.NumberFormat
    32. Intl.PluralRules
    33. Intl.RelativeTimeFormat
    34. Iterator
    35. JSON
    36. Map
    37. Math
    38. NaN
    39. Number
    40. Object
    41. Promise
    42. Proxy
    43. RangeError
    44. ReferenceError
    45. Reflect
    46. RegExp
    47. Set
    48. SharedArrayBuffer
    49. String
    50. Symbol
    51. SyntaxError
    52. TypeError
    53. TypedArray
    54. URIError
    55. Uint16Array
    56. Uint32Array
    57. Uint8Array
    58. Uint8ClampedArray
    59. WeakMap
    60. WeakSet
    61. WebAssembly
    62. decodeURI()
    63. decodeURIComponent()
    64. encodeURI()
    65. encodeURIComponent()
    66. escape()
    67. eval()
    68. globalThis
    69. isFinite()
    70. isNaN()
    71. null
    72. parseFloat()
    73. parseInt()
    74. undefined
    75. unescape()
    76. uneval()
  9. 表达式 & 运算符
    1. 算术运算符
    2. Array comprehensions
    3. 赋值运算符
    4. Bitwise operators
    5. 逗号运算符
    6. Comparison operators
    7. 条件 (三元) 运算符
    8. Destructuring assignment
    9. Expression closures
    10. Function expression
    11. Generator comprehensions
    12. Grouping operator
    13. Legacy generator function expression
    14. Logical operators
    15. Nullish coalescing operator
    16. Object initializer
    17. 运算符优先级
    18. Optional chaining
    19. Pipeline operator
    20. 特性访问器
    21. 传播句法
    22. 异步函数表达式
    23. await
    24. class expression
    25. delete operator
    26. function* 表达式
    27. in operator
    28. instanceof
    29. new operator
    30. new.target
    31. super
    32. this
    33. typeof
    34. void 运算符
    35. yield
    36. yield*
  10. 语句 & 声明
    1. Legacy generator function
    2. async function
    3. block
    4. break
    5. class
    6. const
    7. continue
    8. debugger
    9. default
    10. do...while
    11. empty
    12. export
    13. for
    14. for await...of
    15. for each...in
    16. for...in
    17. for...of
    18. 函数声明
    19. function*
    20. if...else
    21. import
    22. import.meta
    23. label
    24. let
    25. return
    26. switch
    27. throw
    28. try...catch
    29. var
    30. while
    31. with
  11. 函数
    1. 箭头函数表达式
    2. 默认参数
    3. 方法定义
    4. 其余参数
    5. 自变量对象
    6. getter
    7. setter
    1. Class fields
    2. 构造函数
    3. extends
    4. static
  12. 错误
    1. Error: Permission denied to access property "x"
    2. InternalError: too much recursion
    3. RangeError: argument is not a valid code point
    4. RangeError: invalid array length
    5. RangeError: invalid date
    6. RangeError: precision is out of range
    7. RangeError: radix must be an integer
    8. RangeError: repeat count must be less than infinity
    9. RangeError: repeat count must be non-negative
    10. ReferenceError: "x" is not defined
    11. ReferenceError: assignment to undeclared variable "x"
    12. ReferenceError: can't access lexical declaration`X' before initialization
    13. ReferenceError: deprecated caller or arguments usage
    14. ReferenceError: invalid assignment left-hand side
    15. ReferenceError: reference to undefined property "x"
    16. SyntaxError: "0"-prefixed octal literals and octal escape seq. are deprecated
    17. SyntaxError: "use strict" not allowed in function with non-simple parameters
    18. SyntaxError: "x" is a reserved identifier
    19. SyntaxError: JSON.parse: bad parsing
    20. SyntaxError: Malformed formal parameter
    21. SyntaxError: Unexpected token
    22. SyntaxError: Using //@ to indicate sourceURL pragmas is deprecated. Use //# instead
    23. SyntaxError: a declaration in the head of a for-of loop can't have an initializer
    24. SyntaxError: applying the 'delete' operator to an unqualified name is deprecated
    25. SyntaxError: for-in loop head declarations may not have initializers
    26. SyntaxError: function statement requires a name
    27. SyntaxError: identifier starts immediately after numeric literal
    28. SyntaxError: illegal character
    29. SyntaxError: invalid regular expression flag "x"
    30. SyntaxError: missing ) after argument list
    31. SyntaxError: missing ) after condition
    32. SyntaxError: missing : after property id
    33. SyntaxError: missing ; before statement
    34. SyntaxError: missing = in const declaration
    35. SyntaxError: missing ] after element list
    36. SyntaxError: missing formal parameter
    37. SyntaxError: missing name after . operator
    38. SyntaxError: missing variable name
    39. SyntaxError: missing } after function body
    40. SyntaxError: missing } after property list
    41. SyntaxError: redeclaration of formal parameter "x"
    42. SyntaxError: return not in function
    43. SyntaxError: test for equality (==) mistyped as assignment (=)?
    44. SyntaxError: unterminated string literal
    45. TypeError: "x" has no properties
    46. TypeError: "x" is (not) "y"
    47. TypeError: "x" is not a constructor
    48. TypeError: "x" is not a function
    49. TypeError: "x" is not a non-null object
    50. TypeError: "x" is read-only
    51. TypeError: 'x' is not iterable
    52. TypeError: More arguments needed
    53. TypeError: Reduce of empty array with no initial value
    54. TypeError: X.prototype.y called on incompatible type
    55. TypeError: can't access dead object
    56. TypeError: can't access property "x" of "y"
    57. TypeError: can't assign to property "x" on "y": not an object
    58. TypeError: can't define property "x": "obj" is not extensible
    59. TypeError: can't delete non-configurable array element
    60. TypeError: can't redefine non-configurable property "x"
    61. TypeError: cannot use 'in' operator to search for 'x' in 'y'
    62. TypeError: cyclic object value
    63. TypeError: invalid 'instanceof' operand 'x'
    64. TypeError: invalid Array.prototype.sort argument
    65. TypeError: invalid arguments
    66. TypeError: invalid assignment to const "x"
    67. TypeError: property "x" is non-configurable and can't be deleted
    68. TypeError: setting getter-only property "x"
    69. TypeError: variable "x" redeclares argument
    70. URIError: malformed URI sequence
    71. Warning: -file- is being assigned a //# sourceMappingURL, but already has one
    72. Warning: 08/09 is not a legal ECMA-262 octal constant
    73. Warning: Date.prototype.toLocaleFormat is deprecated
    74. Warning: JavaScript 1.6's for-each-in loops are deprecated
    75. Warning: String.x is deprecated; use String.prototype.x instead
    76. Warning: expression closures are deprecated
    77. Warning: unreachable code after return statement
  13. 杂项
    1. JavaScript technologies overview
    2. 词汇语法
    3. JavaScript 数据结构
    4. Enumerability and ownership of properties
    5. Iteration protocols
    6. 严格模式
    7. Transitioning to strict mode
    8. Template literals
    9. 弃用特征