语法和类型
本章讨论 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.
const Früh = "foobar";
但是,变量 früh
与 Frü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:
// 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.
/* You can't, however, /* nest comments */ SyntaxError */
在这种情况下,你需要分解 */
模式。例如,通过插入反斜杠:
¥In this case, you need to break up the */
pattern. For example, by inserting a backslash:
/* 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.
声明
变量
¥Variables
你可以使用变量作为应用中值的符号名称。变量的名称称为 identifiers,符合一定的规则。
¥You use variables as symbolic names for values in your application. The names of variables, called identifiers, conform to certain rules.
JavaScript 标识符通常以字母、下划线 (_
) 或美元符号 ($
) 开头。后续字符也可以是数字 (0
– 9
)。由于 JavaScript 区分大小写,因此字母包括字符 A
到 Z
(大写)以及 a
到 z
(小写)。
¥A JavaScript identifier usually starts with a letter, underscore (_
), or dollar sign ($
). Subsequent characters can also be digits (0
– 9
). 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_hits
、temp99
、$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
。此语法可用于声明局部变量和全局变量,具体取决于执行上下文。 - 使用关键字
const
或let
。例如,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
,而初始化程序会为该变量分配一个值。在 var
和 let
声明中,初始化器是可选的。如果声明变量时没有初始化,则为其分配值 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
.
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.
const x; // SyntaxError: Missing initializer in const declaration
变量范围
¥Variable scope
变量可能属于以下 scopes 之一:
¥A variable may belong to one of the following scopes:
- 全球范围:在脚本模式下运行的所有代码的默认范围。
- 模块范围:在模块模式下运行的代码的范围。
- 功能范围:使用 function 创建的范围。
此外,使用 let
或 const
声明的变量可以属于附加作用域:
¥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.
let
和 const
声明的范围也可以限定在声明它们的 块语句 内。
¥let
and const
declarations can also be scoped to the block statement that they are declared in.
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.
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.
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:
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.
let
和 const
是否被提升是一个定义争论的问题。在变量声明之前引用块中的变量始终会导致 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.
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.
因此,你可以通过指定 window
或 frame
名称从另一个窗口或框架访问在一个窗口或框架中声明的全局变量。例如,如果在文档中声明了一个名为 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.
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:
// 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.
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.
const MY_ARRAY = ["HTML", "CSS"];
MY_ARRAY.push("JAVASCRIPT");
console.log(MY_ARRAY); // ['HTML', 'CSS', 'JAVASCRIPT'];
数据结构和类型
数据类型
¥Data types
最新的 ECMAScript 标准定义了八种数据类型:
¥The latest ECMAScript standard defines eight data types:
- primitives 的七种数据类型:
- 和 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:
let answer = 42;
之后,你可以为同一变量分配一个字符串值,例如:
¥And later, you could assign the same variable a string value, for example:
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:
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:
"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.
parseInt("101", 2); // 5
从字符串中检索数字的另一种方法是使用 +
(一元加)运算符:
¥An alternative method of retrieving a number from a string is with the +
(unary plus) operator:
"1.1" + "1.1"; // '1.11.1'
(+"1.1") + (+"1.1"); // 2.2
// Note: the parentheses are added for clarity, not required.
文字
数组文字
¥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:
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. SeeArray
and Indexed collections for details onArray
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:
const fish = ["Lion", , "Angel"];
当你记录该数组时,你将看到:
¥When you log this array, you will see:
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.
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.
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.
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.
diffconst 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.
const myList = ["home", /* empty */, "school", /* empty */, ];
布尔文字
¥Boolean literals
布尔类型有两个文字值:true
和 false
。
¥The Boolean type has two literal values: true
and false
.
注意:不要将原始布尔值
true
和false
与Boolean
对象的 true 和 false 值混淆。¥Note: Do not confuse the primitive Boolean values
true
andfalse
with the true and false values of theBoolean
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
)表示它是八进制的。八进制整数文字只能包含数字0
–7
。 - 前导
0x
(或0X
)表示十六进制整数文字。十六进制整数可以包含数字 (0
–9
) 和字母a
–f
和A
–F
。(字符的大小写不会改变其值。因此:0xa
=0xA
=10
和0xf
=0xF
=15
。) - 前导
0b
(或0B
)表示二进制整数文字。二进制整数文字只能包含数字0
和1
。 - 整数文字上的尾随
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:
- 无符号十进制整数,
- 小数点(
.
), - 一个分数(另一个小数),
- 一个指数。
指数部分是 e
或 E
后跟一个可以带符号的整数(前面是 +
或 -
)。浮点文字必须至少有一位数字,并且是小数点或 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:
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
).
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.
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.
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 ([]
).
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.
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,
};
正则表达式文字
字符串文字
¥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:
'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:
// 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.)
// 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" 函数来解析它。标记模板只是一种更简洁和语义化的方式来调用处理字符串和一组相关值的函数。模板标记函数的名称位于模板文字之前 - 如下例所示,其中模板标记函数名为 print
。print
函数将插入参数并序列化可能出现的任何对象或数组,避免讨厌的 [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]
.
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:
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:
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.
"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 编码的字符,由 0 和 377 之间最多三个八进制数字 XXX 指定。例如,\251 是版权符号的八进制序列。 |
\xXX |
由 00 和 FF 之间的两个十六进制数字 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:
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:
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.
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.