语法和类型

本章讨论 JavaScript 的基本语法、变量声明、数据类型和文字。

¥This chapter discusses JavaScript's basic grammar, variable declarations, data types and literals.

基本

¥Basics

JavaScript 的大部分语法借鉴了 Java、C 和 C++,但它也受到了 Awk、Perl 和 Python 的影响。

¥JavaScript borrows most of its syntax from Java, C, and C++, but it has also been influenced by Awk, Perl, and Python.

JavaScript 区分大小写并使用 Unicode 字符集。例如,单词 Früh(德语中的意思是 "early")可以用作变量名称。

¥JavaScript is case-sensitive and uses the Unicode character set. For example, the word Früh (which means "early" in German) could be used as a variable name.

js
const Früh = "foobar";

但是,变量 frühFrüh 不同,因为 JavaScript 区分大小写。

¥But, the variable früh is not the same as Früh because JavaScript is case sensitive.

在 JavaScript 中,指令称为 statements,并用分号 (;) 分隔。

¥In JavaScript, instructions are called statements and are separated by semicolons (;).

如果语句写在自己的行上,则语句后面不需要分号。但如果一行中需要多个语句,则必须用分号分隔它们。

¥A semicolon is not necessary after a statement if it is written on its own line. But if more than one statement on a line is desired, then they must be separated by semicolons.

注意:ECMAScript 还具有自动插入分号 (ASI) 来结束语句的规则。(有关更多信息,请参阅有关 JavaScript 的 词汇语法 的详细参考。)

¥Note: ECMAScript also has rules for automatic insertion of semicolons (ASI) to end statements. (For more information, see the detailed reference about JavaScript's lexical grammar.)

然而,最好的做法是在语句后始终写上分号,即使不是严格需要的。这种做法减少了代码中出现错误的机会。

¥It is considered best practice, however, to always write a semicolon after a statement, even when it is not strictly needed. This practice reduces the chances of bugs getting into the code.

JavaScript 脚本的源文本从左到右扫描,并转换为一系列输入元素,包括标记、控制字符、行终止符、注释或 whitespace。(空格、制表符和换行符被视为空白。)

¥The source text of JavaScript script gets scanned from left to right, and is converted into a sequence of input elements which are tokens, control characters, line terminators, comments, or whitespace. (Spaces, tabs, and newline characters are considered whitespace.)

评论

¥Comments

注释的语法与 C++ 和许多其他语言中的相同:

¥The syntax of comments is the same as in C++ and in many other languages:

js
// a one line comment

/* this is a longer,

 * multi-line comment
 */

你不能嵌套块注释。当你不小心在评论中包含 */ 序列时,通常会发生这种情况,这将终止评论。

¥You can't nest block comments. This often happens when you accidentally include a */ sequence in your comment, which will terminate the comment.

js
/* You can't, however, /* nest comments */ SyntaxError */

在这种情况下,你需要分解 */ 模式。例如,通过插入反斜杠:

¥In this case, you need to break up the */ pattern. For example, by inserting a backslash:

js
/* You can /* nest comments *\/ by escaping slashes */

注释的行为类似于空格,并且在脚本执行期间被丢弃。

¥Comments behave like whitespace, and are discarded during script execution.

注意:你可能还会在某些 JavaScript 文件的开头看到第三种类型的注释语法,如下所示:#!/usr/bin/env node

¥Note: You might also see a third type of comment syntax at the start of some JavaScript files, which looks something like this: #!/usr/bin/env node.

这称为 hashbang 注释语法,是一种特殊注释,用于指定应执行脚本的特定 JavaScript 引擎的路径。详细信息请参见 哈希邦评论

¥This is called hashbang comment syntax, and is a special comment used to specify the path to a particular JavaScript engine that should execute the script. See Hashbang comments for more details.

声明

¥Declarations

JavaScript 具有三种变量声明。

¥JavaScript has three kinds of variable declarations.

var

声明一个变量,可以选择将其初始化为一个值。

let

声明一个块范围的局部变量,可以选择将其初始化为一个值。

const

声明一个块范围的只读命名常量。

变量

¥Variables

你可以使用变量作为应用中值的符号名称。变量的名称称为 identifiers,符合一定的规则。

¥You use variables as symbolic names for values in your application. The names of variables, called identifiers, conform to certain rules.

JavaScript 标识符通常以字母、下划线 (_) 或美元符号 ($) 开头。后续字符也可以是数字 (09)。由于 JavaScript 区分大小写,因此字母包括字符 AZ(大写)以及 az(小写)。

¥A JavaScript identifier usually starts with a letter, underscore (_), or dollar sign ($). Subsequent characters can also be digits (09). Because JavaScript is case sensitive, letters include the characters A through Z (uppercase) as well as a through z (lowercase).

你可以在标识符中使用大多数 Unicode 字母,例如 åü。(有关更多详细信息,请参阅 词汇语法 参考资料。)你还可以使用 Unicode 转义序列 来表示标识符中的字符。

¥You can use most Unicode letters such as å and ü in identifiers. (For more details, see the lexical grammar reference.) You can also use Unicode escape sequences to represent characters in identifiers.

法定名称的一些示例包括 Number_hitstemp99$credit_name

¥Some examples of legal names are Number_hits, temp99, $credit, and _name.

声明变量

¥Declaring variables

你可以通过两种方式声明变量:

¥You can declare a variable in two ways:

  • 使用关键字 var。例如,var x = 42。此语法可用于声明局部变量和全局变量,具体取决于执行上下文。
  • 使用关键字 constlet。例如,let y = 13。此语法可用于声明块作用域局部变量。(参见下面的 变量范围。)

你可以使用 解构赋值 语法声明变量来解压值。例如,const { bar } = foo。这将创建一个名为 bar 的变量,并为其分配与对象 foo 中的同名键对应的值。

¥You can declare variables to unpack values using the destructuring assignment syntax. For example, const { bar } = foo. This will create a variable named bar and assign to it the value corresponding to the key of the same name from our object foo.

变量应始终在使用之前声明。JavaScript 过去允许分配给未声明的变量,这会创建 未声明的全球 变量。这是 严格模式 中的错误,应该完全避免。

¥Variables should always be declared before they are used. JavaScript used to allow assigning to undeclared variables, which creates an undeclared global variable. This is an error in strict mode and should be avoided altogether.

声明和初始化

¥Declaration and initialization

在像 let x = 42 这样的语句中,let x 部分称为声明,= 42 部分称为初始值设定项。该声明允许稍后在代码中访问该变量,而不会抛出 ReferenceError,而初始化程序会为该变量分配一个值。在 varlet 声明中,初始化器是可选的。如果声明变量时没有初始化,则为其分配值 undefined

¥In a statement like let x = 42, the let x part is called a declaration, and the = 42 part is called an initializer. The declaration allows the variable to be accessed later in code without throwing a ReferenceError, while the initializer assigns a value to the variable. In var and let declarations, the initializer is optional. If a variable is declared without an initializer, it is assigned the value undefined.

js
let x;
console.log(x); // logs "undefined"

本质上,let x = 42 等同于 let x; x = 42

¥In essence, let x = 42 is equivalent to let x; x = 42.

const 声明始终需要一个初始化程序,因为它们禁止在声明后进行任何类型的赋值,并且使用 undefined 隐式初始化它可能是程序员的错误。

¥const declarations always need an initializer, because they forbid any kind of assignment after declaration, and implicitly initializing it with undefined is likely a programmer mistake.

js
const x; // SyntaxError: Missing initializer in const declaration

变量范围

¥Variable scope

变量可能属于以下 scopes 之一:

¥A variable may belong to one of the following scopes:

  • 全球范围:在脚本模式下运行的所有代码的默认范围。
  • 模块范围:在模块模式下运行的代码的范围。
  • 功能范围:使用 function 创建的范围。

此外,使用 letconst 声明的变量可以属于附加作用域:

¥In addition, variables declared with let or const can belong to an additional scope:

  • 块范围:使用一对大括号(block)创建的范围。

当你在任何函数外部声明变量时,它称为全局变量,因为它可供当前文档中的任何其他代码使用。当你在函数内声明变量时,它称为局部变量,因为它仅在该函数内可用。

¥When you declare a variable outside of any function, it is called a global variable, because it is available to any other code in the current document. When you declare a variable within a function, it is called a local variable, because it is available only within that function.

letconst 声明的范围也可以限定在声明它们的 块语句 内。

¥let and const declarations can also be scoped to the block statement that they are declared in.

js
if (Math.random() > 0.5) {
  const y = 5;
}
console.log(y); // ReferenceError: y is not defined

但是,使用 var 创建的变量不是块作用域的,而只是块所在函数(或全局作用域)的本地变量。

¥However, variables created with var are not block-scoped, but only local to the function (or global scope) that the block resides within.

例如,以下代码将记录 5,因为 x 的范围是全局上下文(如果代码是函数的一部分,则为函数上下文)。x 的范围不限于紧邻的 if 语句块。

¥For example, the following code will log 5, because the scope of x is the global context (or the function context if the code is part of a function). The scope of x is not limited to the immediate if statement block.

js
if (true) {
  var x = 5;
}
console.log(x); // x is 5

变量提升

¥Variable hoisting

var 声明的变量是 hoisted,这意味着你可以在其范围内的任何位置引用该变量,即使尚未到达其声明。你可以将 var 声明视为 "lifted" 到其函数或全局范围的顶部。但是,如果在声明变量之前访问变量,则该值始终为 undefined,因为仅提升其声明和默认初始化(使用 undefined),而不提升其赋值。

¥var-declared variables are hoisted, meaning you can refer to the variable anywhere in its scope, even if its declaration isn't reached yet. You can see var declarations as being "lifted" to the top of its function or global scope. However, if you access a variable before it's declared, the value is always undefined, because only its declaration and default initialization (with undefined) is hoisted, but not its value assignment.

js
console.log(x === undefined); // true
var x = 3;

(function () {
  console.log(x); // undefined
  var x = "local value";
})();

上述示例将被解释为相同:

¥The above examples will be interpreted the same as:

js
var x;
console.log(x === undefined); // true
x = 3;

(function () {
  var x;
  console.log(x); // undefined
  x = "local value";
})();

由于提升,函数中的所有 var 语句应尽可能放置在靠近函数顶部的位置。此最佳实践提高了代码的清晰度。

¥Because of hoisting, all var statements in a function should be placed as near to the top of the function as possible. This best practice increases the clarity of the code.

letconst 是否被提升是一个定义争论的问题。在变量声明之前引用块中的变量始终会导致 ReferenceError,因为从块的开头到处理声明为止,该变量位于“颞死区”中。

¥Whether let and const are hoisted is a matter of definition debate. Referencing the variable in the block before the variable declaration always results in a ReferenceError, because the variable is in a "temporal dead zone" from the start of the block until the declaration is processed.

js
console.log(x); // ReferenceError
const x = 3;

console.log(y); // ReferenceError
let y = 3;

var 声明不同,var 声明仅提升声明而不提升其值,而 函数声明 是完全提升的 - 你可以安全地在其范围内的任何位置调用该函数。有关更多讨论,请参阅 hoisting 术语表条目。

¥Unlike var declarations, which only hoist the declaration but not its value, function declarations are hoisted entirely — you can safely call the function anywhere in its scope. See the hoisting glossary entry for more discussion.

全局变量

¥Global variables

全局变量实际上是全局对象的属性。

¥Global variables are in fact properties of the global object.

在网页中,全局对象是 window,因此可以使用 window.variable 语法读取和设置全局变量。在所有环境中,globalThis 变量(其本身是全局变量)可用于读取和设置全局变量。这是为了在各种 JavaScript 运行时之间提供一致的接口。

¥In web pages, the global object is window, so you can read and set global variables using the window.variable syntax. In all environments, the globalThis variable (which itself is a global variable) may be used to read and set global variables. This is to provide a consistent interface among various JavaScript runtimes.

因此,你可以通过指定 windowframe 名称从另一个窗口或框架访问在一个窗口或框架中声明的全局变量。例如,如果在文档中声明了一个名为 phoneNumber 的变量,则可以在 iframe 中将该变量引用为 parent.phoneNumber

¥Consequently, you can access global variables declared in one window or frame from another window or frame by specifying the window or frame name. For example, if a variable called phoneNumber is declared in a document, you can refer to this variable from an iframe as parent.phoneNumber.

常数

¥Constants

你可以使用 const 关键字创建只读的命名常量。常量标识符的语法与任何变量标识符相同:它必须以字母、下划线或美元符号 ($) 开头,并且可以包含字母、数字或下划线字符。

¥You can create a read-only, named constant with the const keyword. The syntax of a constant identifier is the same as any variable identifier: it must start with a letter, underscore, or dollar sign ($), and can contain alphabetic, numeric, or underscore characters.

js
const PI = 3.14;

常量不能通过赋值来更改值,也不能在脚本运行时重新声明。它必须被初始化为一个值。常量的作用域规则与 let 块作用域变量的作用域规则相同。

¥A constant cannot change value through assignment or be re-declared while the script is running. It must be initialized to a value. The scope rules for constants are the same as those for let block-scope variables.

不能在同一作用域中声明与函数或变量同名的常量。例如:

¥You cannot declare a constant with the same name as a function or variable in the same scope. For example:

js
// THIS WILL CAUSE AN ERROR
function f() {}
const f = 5;

// THIS WILL CAUSE AN ERROR TOO
function f() {
  const g = 5;
  var g;
}

但是,const 只能防止重新分配,但不能防止突变。分配给常量的对象的属性不受保护,因此执行以下语句没有问题。

¥However, const only prevents re-assignments, but doesn't prevent mutations. The properties of objects assigned to constants are not protected, so the following statement is executed without problems.

js
const MY_OBJECT = { key: "value" };
MY_OBJECT.key = "otherValue";

另外,数组的内容不受保护,因此执行以下语句不会出现问题。

¥Also, the contents of an array are not protected, so the following statement is executed without problems.

js
const MY_ARRAY = ["HTML", "CSS"];
MY_ARRAY.push("JAVASCRIPT");
console.log(MY_ARRAY); // ['HTML', 'CSS', 'JAVASCRIPT'];

数据结构和类型

¥Data structures and types

数据类型

¥Data types

最新的 ECMAScript 标准定义了八种数据类型:

¥The latest ECMAScript standard defines eight data types:

  • primitives 的七种数据类型:
    1. Booleantruefalse
    2. null。表示空值的特殊关键字。(由于 JavaScript 区分大小写,nullNullNULL 或任何其他变体不同。)
    3. undefined。其值未定义的顶层属性。
    4. Number。整数或浮点数。例如:423.14159
    5. BigInt。任意精度的整数。例如:9007199254740992n
    6. String。表示文本值的字符序列。例如:"Howdy"
    7. 符合。实例唯一且不可变的数据类型。
  • Object

尽管这些数据类型相对较少,但它们使你能够对应用执行有用的操作。函数 是该语言的其他基本元素。虽然函数在技术上是一种对象,但你可以将对象视为值的命名容器,将函数视为脚本可以执行的过程。

¥Although these data types are relatively few, they enable you to perform useful operations with your applications. Functions are the other fundamental elements of the language. While functions are technically a kind of object, you can think of objects as named containers for values, and functions as procedures that your script can perform.

数据类型转换

¥Data type conversion

JavaScript 是一种动态类型语言。这意味着你在声明变量时不必指定变量的数据类型。这也意味着在脚本执行期间数据类型会根据需要自动转换。

¥JavaScript is a dynamically typed language. This means you don't have to specify the data type of a variable when you declare it. It also means that data types are automatically converted as-needed during script execution.

因此,例如,你可以按如下方式定义变量:

¥So, for example, you could define a variable as follows:

js
let answer = 42;

之后,你可以为同一变量分配一个字符串值,例如:

¥And later, you could assign the same variable a string value, for example:

js
answer = "Thanks for all the fish!";

由于 JavaScript 是动态类型的,因此该赋值不会导致错误消息。

¥Because JavaScript is dynamically typed, this assignment does not cause an error message.

数字和 '*' 运算符

¥Numbers and the '+' operator

在涉及带有 + 运算符的数字和字符串值的表达式中,JavaScript 将数字值转换为字符串。例如,考虑以下语句:

¥In expressions involving numeric and string values with the + operator, JavaScript converts numeric values to strings. For example, consider the following statements:

js
x = "The answer is " + 42; // "The answer is 42"
y = 42 + " is the answer"; // "42 is the answer"
z = "37" + 7; // "377"

对于所有其他运算符,JavaScript 不会将数值转换为字符串。例如:

¥With all other operators, JavaScript does not convert numeric values to strings. For example:

js
"37" - 7; // 30
"37" * 7; // 259

将字符串转换为数字

¥Converting strings to numbers

如果表示数字的值在内存中以字符串形式存在,则有一些转换方法。

¥In the case that a value representing a number is in memory as a string, there are methods for conversion.

parseInt 仅返回整数,因此它对于小数的使用会减少。

¥parseInt only returns whole numbers, so its use is diminished for decimals.

注意:此外,parseInt 的最佳实践是始终包含基数参数。基数参数用于指定要使用的数值系统。

¥Note: Additionally, a best practice for parseInt is to always include the radix parameter. The radix parameter is used to specify which numerical system is to be used.

js
parseInt("101", 2); // 5

从字符串中检索数字的另一种方法是使用 +(一元加)运算符:

¥An alternative method of retrieving a number from a string is with the + (unary plus) operator:

js
"1.1" + "1.1"; // '1.11.1'
(+"1.1") + (+"1.1"); // 2.2
// Note: the parentheses are added for clarity, not required.

文字

¥Literals

文字代表 JavaScript 中的值。这些是你在脚本中实际提供的固定值(而不是变量)。本节描述以下类型的文字:

¥Literals represent values in JavaScript. These are fixed values—not variables—that you literally provide in your script. This section describes the following types of literals:

数组文字

¥Array literals

数组文字是零个或多个表达式的列表,每个表达式代表一个数组元素,括在方括号 ([]) 中。当你使用数组文字创建数组时,它会使用指定的值作为其元素进行初始化,并将其 length 设置为指定的参数数量。

¥An array literal is a list of zero or more expressions, each of which represents an array element, enclosed in square brackets ([]). When you create an array using an array literal, it is initialized with the specified values as its elements, and its length is set to the number of arguments specified.

以下示例创建包含三个元素的 coffees 数组和包含三个元素的 length

¥The following example creates the coffees array with three elements and a length of three:

js
const coffees = ["French Roast", "Colombian", "Kona"];

每次计算文字时,数组文字都会创建一个新的数组对象。例如,在脚本加载时创建一次在全局范围内使用文字定义的数组。但是,如果数组文字位于函数内部,则每次调用该函数时都会实例化一个新数组。

¥An array literal creates a new array object every time the literal is evaluated. For example, an array defined with a literal in the global scope is created once when the script loads. However, if the array literal is inside a function, a new array is instantiated every time that function is called.

注意:数组文字创建 Array 个对象。有关 Array 对象的详细信息,请参阅 Array索引集合

¥Note: Array literals create Array objects. See Array and Indexed collections for details on Array objects.

数组文字中的额外逗号

¥Extra commas in array literals

如果在数组文字中连续放置两个逗号,则数组会为未指定的元素留下一个空槽。以下示例创建 fish 数组:

¥If you put two commas in a row in an array literal, the array leaves an empty slot for the unspecified element. The following example creates the fish array:

js
const fish = ["Lion", , "Angel"];

当你记录该数组时,你将看到:

¥When you log this array, you will see:

js
console.log(fish);
// [ 'Lion', <1 empty item>, 'Angel' ]

注意,第二项是 "empty",与实际的 undefined 值并不完全相同。当使用像 Array.prototype.map 这样的数组遍历方法时,空槽会被跳过。然而,索引访问 fish[1] 仍然返回 undefined

¥Note that the second item is "empty", which is not exactly the same as the actual undefined value. When using array-traversing methods like Array.prototype.map, empty slots are skipped. However, index-accessing fish[1] still returns undefined.

如果在元素列表末尾包含尾随逗号,则该逗号将被忽略。

¥If you include a trailing comma at the end of the list of elements, the comma is ignored.

在以下示例中,数组的 length 为 3。没有 myList[3]。列表中的所有其他逗号表示新元素。

¥In the following example, the length of the array is three. There is no myList[3]. All other commas in the list indicate a new element.

js
const myList = ["home", , "school"];

在下面的示例中,数组的 length 为 4,缺少 myList[0]myList[2]

¥In the following example, the length of the array is four, and myList[0] and myList[2] are missing.

js
const myList = [, "home", , "school"];

在下面的示例中,数组的 length 为 4,缺少 myList[1]myList[3]。仅忽略最后一个逗号。

¥In the following example, the length of the array is four, and myList[1] and myList[3] are missing. Only the last comma is ignored.

js
const myList = ["home", , "school", ,];

注意:当你有多行数组时,尾随逗号 有助于保持 git diff 干净,因为将一个项目附加到末尾只会添加一行,但不会修改前一行。

¥Note: Trailing commas help keep git diffs clean when you have a multi-line array, because appending an item to the end only adds one line, but does not modify the previous line.

diff
const myList = [
  "home",
  "school",
+ "hospital",
];

了解额外逗号的行为对于理解 JavaScript 作为一种语言非常重要。

¥Understanding the behavior of extra commas is important to understanding JavaScript as a language.

但是,在编写自己的代码时,你应该将缺少的元素显式声明为 undefined,或者至少插入注释以高亮其缺失。这样做可以提高代码的清晰度和可维护性。

¥However, when writing your own code, you should explicitly declare the missing elements as undefined, or at least insert a comment to highlight its absence. Doing this increases your code's clarity and maintainability.

js
const myList = ["home", /* empty */, "school", /* empty */, ];

布尔文字

¥Boolean literals

布尔类型有两个文字值:truefalse

¥The Boolean type has two literal values: true and false.

注意:不要将原始布尔值 truefalseBoolean 对象的 true 和 false 值混淆。

¥Note: Do not confuse the primitive Boolean values true and false with the true and false values of the Boolean object.

Boolean 对象是原始布尔数据类型的封装器。请参阅 Boolean 了解更多信息。

¥The Boolean object is a wrapper around the primitive Boolean data type. See Boolean for more information.

数字文字

¥Numeric literals

JavaScript 数字文字包括不同基数的整数文字以及以 10 为基数的浮点文字。

¥JavaScript numeric literals include integer literals in different bases as well as floating-point literals in base-10.

请注意,语言规范要求数字文字是无符号的。然而,像 -123.4 这样的代码片段很好,可以被解释为应用于数字文字 123.4 的一元 - 运算符。

¥Note that the language specification requires numeric literals to be unsigned. Nevertheless, code fragments like -123.4 are fine, being interpreted as a unary - operator applied to the numeric literal 123.4.

整数文字

¥Integer literals

整数和 BigInt 文字可以用十进制(基数 10)、十六进制(基数 16)、八进制(基数 8)和二进制(基数 2)编写。

¥Integer and BigInt literals can be written in decimal (base 10), hexadecimal (base 16), octal (base 8) and binary (base 2).

  • 十进制整数文字是不带前导 0(零)的数字序列。
  • 整数文字上的前导 0(零)或前导 0o(或 0O)表示它是八进制的。八进制整数文字只能包含数字 07
  • 前导 0x(或 0X)表示十六进制整数文字。十六进制整数可以包含数字 (09) 和字母 afAF。(字符的大小写不会改变其值。因此:0xa = 0xA = 100xf = 0xF = 15。)
  • 前导 0b(或 0B)表示二进制整数文字。二进制整数文字只能包含数字 01
  • 整数文字上的尾随 n 后缀表示 BigInt 文字。BigInt 文字可以使用上述任何基数。请注意,不允许使用像 0123n 这样的前导零八进制语法,但 0o123n 可以。

整数文字的一些示例是:

¥Some examples of integer literals are:

0, 117, 123456789123456789n             (decimal, base 10)
015, 0001, 0o777777777777n              (octal, base 8)
0x1123, 0x00111, 0x123456789ABCDEFn     (hexadecimal, "hex" or base 16)
0b11, 0b0011, 0b11101001010101010101n   (binary, base 2)

欲了解更多信息,请参阅 词法语法参考中的数字文字

¥For more information, see Numeric literals in the Lexical grammar reference.

浮点文字

¥Floating-point literals

浮点文字可以由以下部分组成:

¥A floating-point literal can have the following parts:

  • 无符号十进制整数,
  • 小数点(.),
  • 一个分数(另一个小数),
  • 一个指数。

指数部分是 eE 后跟一个可以带符号的整数(前面是 +-)。浮点文字必须至少有一位数字,并且是小数点或 e(或 E)。

¥The exponent part is an e or E followed by an integer, which can be signed (preceded by + or -). A floating-point literal must have at least one digit, and either a decimal point or e (or E).

更简洁地说,语法是:

¥More succinctly, the syntax is:

[digits].[digits][(E|e)[(+|-)]digits]

例如:

¥For example:

js
3.1415926
.123456789
3.1E+12
.1e-23

对象字面量

¥Object literals

对象字面量是对象的零对或多对属性名称和关联值的列表,括在大括号 ({}) 中。

¥An object literal is a list of zero or more pairs of property names and associated values of an object, enclosed in curly braces ({}).

警告:不要在语句开头使用对象文字!这将导致错误(或行为不符合你的预期),因为 { 将被解释为块的开头。

¥Warning: Do not use an object literal at the beginning of a statement! This will lead to an error (or not behave as you expect), because the { will be interpreted as the beginning of a block.

以下是对象文字的示例。car 对象的第一个元素定义了一个属性 myCar,并为其分配了一个新字符串 "Saturn";第二个元素,即 getCar 属性,立即被赋予调用函数 (carTypes("Honda")) 的结果;第三个元素,special 属性,使用现有变量 (sales)。

¥The following is an example of an object literal. The first element of the car object defines a property, myCar, and assigns to it a new string, "Saturn"; the second element, the getCar property, is immediately assigned the result of invoking the function (carTypes("Honda")); the third element, the special property, uses an existing variable (sales).

js
const sales = "Toyota";

function carTypes(name) {
  return name === "Honda" ? name : `Sorry, we don't sell ${name}.`;
}

const car = { myCar: "Saturn", getCar: carTypes("Honda"), special: sales };

console.log(car.myCar); // Saturn
console.log(car.getCar); // Honda
console.log(car.special); // Toyota

此外,你可以使用数字或字符串作为属性名称,或者将一个对象嵌套在另一个对象中。以下示例使用这些选项。

¥Additionally, you can use a numeric or string literal for the name of a property or nest an object inside another. The following example uses these options.

js
const car = { manyCars: { a: "Saab", b: "Jeep" }, 7: "Mazda" };

console.log(car.manyCars.b); // Jeep
console.log(car[7]); // Mazda

对象属性名称可以是任何字符串,包括空字符串。如果属性名称不是有效的 JavaScript identifier 或数字,则必须将其括在引号中。

¥Object property names can be any string, including the empty string. If the property name would not be a valid JavaScript identifier or number, it must be enclosed in quotes.

不是有效标识符的属性名称无法作为点 (.) 属性进行访问。

¥Property names that are not valid identifiers cannot be accessed as a dot (.) property.

js
const unusualPropertyNames = {
  '': 'An empty string',
  '!': 'Bang!'
}
console.log(unusualPropertyNames.'');   // SyntaxError: Unexpected string
console.log(unusualPropertyNames.!);    // SyntaxError: Unexpected token !

相反,必须使用方括号符号 ([]) 来访问它们。

¥Instead, they must be accessed with the bracket notation ([]).

js
console.log(unusualPropertyNames[""]); // An empty string
console.log(unusualPropertyNames["!"]); // Bang!

增强的对象文字

¥Enhanced Object literals

对象字面量支持一系列简写语法,包括在构造时设置原型、foo: foo 赋值的简写、定义方法、进行 super 调用以及使用表达式计算属性名称。

¥Object literals support a range of shorthand syntaxes that include setting the prototype at construction, shorthand for foo: foo assignments, defining methods, making super calls, and computing property names with expressions.

总之,它们还使对象文字和类声明更加紧密地结合在一起,并允许基于对象的设计受益于一些相同的便利。

¥Together, these also bring object literals and class declarations closer together, and allow object-based design to benefit from some of the same conveniences.

js
const obj = {
  // __proto__
  __proto__: theProtoObj,
  // Shorthand for 'handler: handler'
  handler,
  // Methods
  toString() {
    // Super calls
    return "d " + super.toString();
  },
  // Computed (dynamic) property names
  ["prop_" + (() => 42)()]: 42,
};

正则表达式文字

¥RegExp literals

正则表达式文字(在详细信息 later 中定义)是包含在斜杠之间的模式。以下是正则表达式文字的示例。

¥A regex literal (which is defined in detail later) is a pattern enclosed between slashes. The following is an example of a regex literal.

js
const re = /ab+c/;

字符串文字

¥String literals

字符串文字是用双引号 (") 或单引号 (') 括起来的零个或多个字符。字符串必须由相同类型的引号(即,两个单引号或两个双引号)分隔。

¥A string literal is zero or more characters enclosed in double (") or single (') quotation marks. A string must be delimited by quotation marks of the same type (that is, either both single quotation marks, or both double quotation marks).

以下是字符串文字的示例:

¥The following are examples of string literals:

js
'foo'
"bar"
'1234'
'one line \n another line'
"Joyo's cat"

除非你特别需要使用 String 对象,否则你应该使用字符串文字。有关 String 对象的详细信息,请参阅 String

¥You should use string literals unless you specifically need to use a String object. See String for details on String objects.

你可以对字符串文字值调用 String 对象的任何方法。JavaScript 自动将字符串文字转换为临时 String 对象,调用该方法,然后丢弃临时 String 对象。你还可以将 length 属性与字符串文字一起使用:

¥You can call any of the String object's methods on a string literal value. JavaScript automatically converts the string literal to a temporary String object, calls the method, then discards the temporary String object. You can also use the length property with a string literal:

js
// Will print the number of symbols in the string including whitespace.
console.log("Joyo's cat".length); // In this case, 10.

模板文字 也可用。模板文字由反引号 (```) (重音) 字符(而不是双引号或单引号)括起来。

¥Template literals are also available. Template literals are enclosed by the back-tick (`) (grave accent) character instead of double or single quotes.

模板文字提供了用于构造字符串的语法糖。(这类似于 Perl、Python 等中的字符串插值功能。)

¥Template literals provide syntactic sugar for constructing strings. (This is similar to string interpolation features in Perl, Python, and more.)

js
// Basic literal string creation
`In JavaScript '\n' is a line-feed.`

// Multiline strings
`In JavaScript, template strings can run
 over multiple lines, but double and single
 quoted strings cannot.`

// String interpolation
const name = 'Lev', time = 'today';
`Hello ${name}, how are you ${time}?`

标记模板 是一种紧凑的语法,用于指定模板文字以及调用 "tag" 函数来解析它。标记模板只是一种更简洁和语义化的方式来调用处理字符串和一组相关值的函数。模板标记函数的名称位于模板文字之前 - 如下例所示,其中模板标记函数名为 printprint 函数将插入参数并序列化可能出现的任何对象或数组,避免讨厌的 [object Object]

¥Tagged templates are a compact syntax for specifying a template literal along with a call to a "tag" function for parsing it. A tagged template is just a more succinct and semantic way to invoke a function that processes a string and a set of relevant values. The name of the template tag function precedes the template literal — as in the following example, where the template tag function is named print. The print function will interpolate the arguments and serialize any objects or arrays that may come up, avoiding the pesky [object Object].

js
const formatArg = (arg) => {
  if (Array.isArray(arg)) {
    // Print a bulleted list
    return arg.map((part) => `- ${part}`).join("\n");
  }
  if (arg.toString === Object.prototype.toString) {
    // This object will be serialized to "[object Object]".
    // Let's print something nicer.
    return JSON.stringify(arg);
  }
  return arg;
};

const print = (segments, ...args) => {
  // For any well-formed template literal, there will always be N args and
  // (N+1) string segments.
  let message = segments[0];
  segments.slice(1).forEach((segment, index) => {
    message += formatArg(args[index]) + segment;
  });
  console.log(message);
};

const todos = [
  "Learn JavaScript",
  "Learn Web APIs",
  "Set up my website",
  "Profit!",
];

const progress = { javascript: 20, html: 50, css: 10 };

print`I need to do:
${todos}
My current progress is: ${progress}
`;

// I need to do:
// - Learn JavaScript
// - Learn Web APIs
// - Set up my website
// - Profit!
// My current progress is: {"javascript":20,"html":50,"css":10}

由于标记模板文字只是函数调用的糖衣,因此你可以将上面的内容重写为等效的函数调用:

¥Since tagged template literals are just sugar of function calls, you can re-write the above as an equivalent function call:

js
print(["I need to do:\n", "\nMy current progress is: ", "\n"], todos, progress);

这可能让人想起 console.log 式的插值:

¥This may be reminiscent of the console.log-style interpolation:

js
console.log("I need to do:\n%o\nMy current progress is: %o\n", todos, progress);

你可以看到带标签的模板比传统的 "formatter" 函数读取起来更自然,在传统的 "formatter" 函数中,变量和模板本身必须单独声明。

¥You can see how the tagged template reads more naturally than a traditional "formatter" function, where the variables and the template itself have to be declared separately.

在字符串中使用特殊字符

¥Using special characters in strings

除了普通字符之外,你还可以在字符串中包含特殊字符,如下例所示。

¥In addition to ordinary characters, you can also include special characters in strings, as shown in the following example.

js
"one line \n another line";

下表列出了可以在 JavaScript 字符串中使用的特殊字符。

¥The following table lists the special characters that you can use in JavaScript strings.

特点 意义
\0 空字节
\b 退格键
\f 换页
\n 新队
\r 回车
\t 标签
\v 垂直标签
\' 撇号或单引号
\" 双引号
\\ 反斜杠字符
\XXX 采用 Latin-1 编码的字符,由 0377 之间最多三个八进制数字 XXX 指定。例如,\251 是版权符号的八进制序列。
\xXX 00FF 之间的两个十六进制数字 XX 指定的具有 Latin-1 编码的字符。例如,\xA9 是版权符号的十六进制序列。
\uXXXX 由四个十六进制数字 XXXX 指定的 Unicode 字符。例如,\u00A9 是版权符号的 Unicode 序列。参见 Unicode 转义序列
\u{XXXXX} Unicode 代码点转义。例如,\u{2F804} 与简单的 Unicode 转义符 \uD87E\uDC04 相同。

转义字符

¥Escaping characters

对于表中未列出的字符,前面的反斜杠将被忽略,但这种用法已被弃用,应该避免。

¥For characters not listed in the table, a preceding backslash is ignored, but this usage is deprecated and should be avoided.

你可以在字符串内插入引号,方法是在字符串前面加上反斜杠。这称为转义引号。例如:

¥You can insert a quotation mark inside a string by preceding it with a backslash. This is known as escaping the quotation mark. For example:

js
const quote = "He read \"The Cremation of Sam McGee\" by R.W. Service.";
console.log(quote);

其结果将是:

¥The result of this would be:

He read "The Cremation of Sam McGee" by R.W. Service.

要在字符串中包含文字反斜杠,必须转义反斜杠字符。例如,要将文件路径 c:\temp 分配给字符串,请使用以下命令:

¥To include a literal backslash inside a string, you must escape the backslash character. For example, to assign the file path c:\temp to a string, use the following:

js
const home = "c:\\temp";

你还可以通过在换行符前面加上反斜杠来转义换行符。反斜杠和换行符都从字符串的值中删除。

¥You can also escape line breaks by preceding them with backslash. The backslash and line break are both removed from the value of the string.

js
const str =
  "this string \
is broken \
across multiple \
lines.";
console.log(str); // this string is broken across multiple lines.

更多信息

¥More information

本章重点介绍声明和类型的基本语法。要了解有关 JavaScript 语言结构的更多信息,另请参阅本指南中的以下章节:

¥This chapter focuses on basic syntax for declarations and types. To learn more about JavaScript's language constructs, see also the following chapters in this guide:

在下一章中,我们将了解控制流构造和错误处理。

¥In the next chapter, we will have a look at control flow constructs and error handling.