表达式和运算符

本章介绍 JavaScript 的表达式和运算符,包括赋值、比较、算术、按位、逻辑、字符串、三元等。

¥This chapter describes JavaScript's expressions and operators, including assignment, comparison, arithmetic, bitwise, logical, string, ternary and more.

从较高层次来看,表达式是解析为值的有效代码单元。有两种类型的表达式:那些有副作用的(例如赋值)和那些纯粹评估的。

¥At a high level, an expression is a valid unit of code that resolves to a value. There are two types of expressions: those that have side effects (such as assigning values) and those that purely evaluate.

表达式 x = 7 是第一种类型的示例。该表达式使用 = 运算符将值 7 赋给变量 x。表达式本身的计算结果为 7

¥The expression x = 7 is an example of the first type. This expression uses the = operator to assign the value seven to the variable x. The expression itself evaluates to 7.

表达式 3 + 4 是第二种类型的示例。此表达式使用 + 运算符将 34 加在一起并生成值 7。但是,如果它最终不是更大构造的一部分(例如,像 const z = 3 + 4 这样的 变量声明),则其结果将立即被丢弃 - 这通常是程序员的错误,因为评估不会产生任何效果。

¥The expression 3 + 4 is an example of the second type. This expression uses the + operator to add 3 and 4 together and produces a value, 7. However, if it's not eventually part of a bigger construct (for example, a variable declaration like const z = 3 + 4), its result will be immediately discarded — this is usually a programmer mistake because the evaluation doesn't produce any effects.

正如上面的例子所说明的,所有复杂的表达式都由运算符连接,例如 =+。在本节中,我们将介绍以下运算符:

¥As the examples above also illustrate, all complex expressions are joined by operators, such as = and +. In this section, we will introduce the following operators:

这些运算符连接由较高优先级运算符或 基本表达 之一形成的操作数。reference 中还提供了完整且详细的运算符和表达式列表。

¥These operators join operands either formed by higher-precedence operators or one of the basic expressions. A complete and detailed list of operators and expressions is also available in the reference.

运算符的优先级决定了它们在计算表达式时的应用顺序。例如:

¥The precedence of operators determines the order they are applied when evaluating an expression. For example:

js
const x = 1 + 2 * 3;
const y = 2 * 3 + 1;

尽管 *+ 的顺序不同,但这两个表达式都会生成 7,因为 * 优先于 +,因此始终首先计算 * 连接的表达式。你可以使用括号覆盖运算符优先级(这会创建 分组表达 — 基本表达式)。要查看完整的运算符优先级表以及各种注意事项,请参阅 运算符优先级参考 页。

¥Despite * and + coming in different orders, both expressions would result in 7 because * has precedence over +, so the *-joined expression will always be evaluated first. You can override operator precedence by using parentheses (which creates a grouped expression — the basic expression). To see a complete table of operator precedence as well as various caveats, see the Operator Precedence Reference page.

JavaScript 具有二元和一元运算符,以及一种特殊的三元运算符,即条件运算符。二元运算符需要两个操作数,一个在运算符之前,一个在运算符之后:

¥JavaScript has both binary and unary operators, and one special ternary operator, the conditional operator. A binary operator requires two operands, one before the operator and one after the operator:

operand1 operator operand2

例如,3 + 4x * y。这种形式称为中缀二元运算符,因为该运算符放置在两个操作数之间。JavaScript 中的所有二元运算符都是中缀。

¥For example, 3 + 4 or x * y. This form is called an infix binary operator, because the operator is placed between two operands. All binary operators in JavaScript are infix.

一元运算符需要单个操作数,位于运算符之前或之后:

¥A unary operator requires a single operand, either before or after the operator:

operator operand
operand operator

例如,x++++xoperator operand 形式称为前缀一元运算符,operand operator 形式称为后缀一元运算符。++-- 是 JavaScript 中唯一的后缀运算符 - 所有其他运算符,如 !typeof 等都是前缀。

¥For example, x++ or ++x. The operator operand form is called a prefix unary operator, and the operand operator form is called a postfix unary operator. ++ and -- are the only postfix operators in JavaScript — all other operators, like !, typeof, etc. are prefix.

赋值运算符

¥Assignment operators

赋值运算符根据其右操作数的值将值分配给其左操作数。简单的赋值运算符是 equal (=),它将右操作数的值赋给左操作数。即,x = f() 是将 f() 的值赋给 x 的赋值表达式。

¥An assignment operator assigns a value to its left operand based on the value of its right operand. The simple assignment operator is equal (=), which assigns the value of its right operand to its left operand. That is, x = f() is an assignment expression that assigns the value of f() to x.

还有复合赋值运算符,它们是下表中列出的操作的简写:

¥There are also compound assignment operators that are shorthand for the operations listed in the following table:

名称 速记运算符 意义
赋值 x = f() x = f()
加法作业 x += f() x = x + f()
减法作业 x -= f() x = x - f()
乘法作业 x *= f() x = x * f()
分区分配 x /= f() x = x / f()
余数分配 x %= f() x = x % f()
求幂赋值 x **= f() x = x ** f()
左移分配 x <<= f() x = x << f()
右移赋值 x >>= f() x = x >> f()
无符号右移赋值 x >>>= f() x = x >>> f()
按位与赋值 x &= f() x = x & f()
按位异或赋值 x ^= f() x = x ^ f()
按位或赋值 x |= f() x = x | f()
逻辑与赋值 x &&= f() x && (x = f())
逻辑或赋值 x ||= f() x || (x = f())
空合并赋值 x ??= f() x ?? (x = f())

分配给属性

¥Assigning to properties

如果表达式的计算结果为 object,则赋值表达式的左侧可以对该表达式的属性进行赋值。例如:

¥If an expression evaluates to an object, then the left-hand side of an assignment expression may make assignments to properties of that expression. For example:

js
const obj = {};

obj.x = 3;
console.log(obj.x); // Prints 3.
console.log(obj); // Prints { x: 3 }.

const key = "y";
obj[key] = 5;
console.log(obj[key]); // Prints 5.
console.log(obj); // Prints { x: 3, y: 5 }.

有关对象的更多信息,请阅读 使用对象

¥For more information about objects, read Working with Objects.

如果表达式的计算结果不是对象,则对该表达式的属性的赋值不会赋值:

¥If an expression does not evaluate to an object, then assignments to properties of that expression do not assign:

js
const val = 0;
val.x = 3;

console.log(val.x); // Prints undefined.
console.log(val); // Prints 0.

严格模式 中,上面的代码会抛出异常,因为无法将属性分配给基元。

¥In strict mode, the code above throws, because one cannot assign properties to primitives.

将值分配给不可修改的属性或没有属性的表达式的属性(nullundefined)是错误的。

¥It is an error to assign values to unmodifiable properties or to properties of an expression without properties (null or undefined).

解构

¥Destructuring

对于更复杂的赋值,解构赋值 语法是一种 JavaScript 表达式,它可以使用反映数组和对象字面量构造的语法从数组或对象中提取数据。

¥For more complex assignments, the destructuring assignment syntax is a JavaScript expression that makes it possible to extract data from arrays or objects using a syntax that mirrors the construction of array and object literals.

在不解构的情况下,需要多个语句才能从数组和对象中提取值:

¥Without destructuring, it takes multiple statements to extract values from arrays and objects:

js
const foo = ["one", "two", "three"];

const one = foo[0];
const two = foo[1];
const three = foo[2];

通过解构,你可以使用单个语句将多个值提取到不同的变量中:

¥With destructuring, you can extract multiple values into distinct variables using a single statement:

js
const [one, two, three] = foo;

评估和嵌套

¥Evaluation and nesting

一般来说,赋值在变量声明中使用(即使用 constletvar)或作为独立语句使用。

¥In general, assignments are used within a variable declaration (i.e., with const, let, or var) or as standalone statements.

js
// Declares a variable x and initializes it to the result of f().
// The result of the x = f() assignment expression is discarded.
let x = f();

x = g(); // Reassigns the variable x to the result of g().

但是,与其他表达式一样,像 x = f() 这样的赋值表达式计算结果为结果值。尽管通常不使用该结果值,但它可以被另一个表达式使用。

¥However, like other expressions, assignment expressions like x = f() evaluate into a result value. Although this result value is usually not used, it can then be used by another expression.

在其他表达式中链接赋值或嵌套赋值可能会导致令人惊讶的行为。因此,一些 JavaScript 样式指南 阻止链接或嵌套分配。然而,赋值链和嵌套有时可能会发生,因此了解它们的工作原理非常重要。

¥Chaining assignments or nesting assignments in other expressions can result in surprising behavior. For this reason, some JavaScript style guides discourage chaining or nesting assignments. Nevertheless, assignment chaining and nesting may occur sometimes, so it is important to be able to understand how they work.

通过链接或嵌套赋值表达式,其结果本身可以分配给另一个变量。它可以被记录,可以放入数组文字或函数调用中,等等。

¥By chaining or nesting an assignment expression, its result can itself be assigned to another variable. It can be logged, it can be put inside an array literal or function call, and so on.

js
let x;
const y = (x = f()); // Or equivalently: const y = x = f();
console.log(y); // Logs the return value of the assignment x = f().

console.log(x = f()); // Logs the return value directly.

// An assignment expression can be nested in any place
// where expressions are generally allowed,
// such as array literals' elements or as function calls' arguments.
console.log([0, x = f(), 0]);
console.log(f(0, x = f(), 0));

评估结果与上表中 "意义" 列中 = 符号右侧的表达式匹配。这意味着 x = f() 计算为 f() 的结果,x += f() 计算为所得总和 x + f()x **= f() 计算为所得幂 x ** f(),依此类推。

¥The evaluation result matches the expression to the right of the = sign in the "Meaning" column of the table above. That means that x = f() evaluates into whatever f()'s result is, x += f() evaluates into the resulting sum x + f(), x **= f() evaluates into the resulting power x ** f(), and so on.

对于逻辑赋值 x &&= f()x ||= f()x ??= f(),返回值是没有赋值的逻辑运算的返回值,因此分别是 x && f()x || f()x ?? f()

¥In the case of logical assignments, x &&= f(), x ||= f(), and x ??= f(), the return value is that of the logical operation without the assignment, so x && f(), x || f(), and x ?? f(), respectively.

当链接这些不带括号或其他分组运算符(如数组文字)的表达式时,赋值表达式从右到左分组(它们是 right-associative),但它们是从左到右计算的。

¥When chaining these expressions without parentheses or other grouping operators like array literals, the assignment expressions are grouped right to left (they are right-associative), but they are evaluated left to right.

请注意,对于除 = 本身之外的所有赋值运算符,结果值始终基于运算前操作数的值。

¥Note that, for all assignment operators other than = itself, the resulting values are always based on the operands' values before the operation.

例如,假设已声明以下函数 fg 以及变量 xy

¥For example, assume that the following functions f and g and the variables x and y have been declared:

js
function f() {
  console.log("F!");
  return 2;
}
function g() {
  console.log("G!");
  return 3;
}
let x, y;

考虑这三个例子:

¥Consider these three examples:

js
y = x = f();
y = [f(), x = g()];
x[f()] = g();

评价例 1

¥Evaluation example 1

y = x = f() 等价于 y = (x = f()),因为赋值运算符 =right-associative。但是,它是从左到右计算的:

¥y = x = f() is equivalent to y = (x = f()), because the assignment operator = is right-associative. However, it evaluates from left to right:

  1. 赋值表达式 y = x = f() 开始计算。
    1. 该赋值左侧的 y 计算结果为对名为 y 的变量的引用。
    2. 赋值表达式 x = f() 开始计算。
      1. 该赋值左侧的 x 计算结果为对名为 x 的变量的引用。
      2. 函数调用 f() 将 "F!" 打印到控制台,然后计算结果为数字 2
      3. f()2 结果被分配给 x
    3. 赋值表达式 x = f() 现已完成求值;其结果是 x 的新值,即 2
    4. 2 结果也依次分配给 y
  2. 赋值表达式 y = x = f() 现已完成求值;它的结果是 y 的新值 - 恰好是 2xy 分配给 2,控制台打印了 "F!"。

评价例 2

¥Evaluation example 2

y = [ f(), x = g() ] 也从左到右评估:

¥y = [ f(), x = g() ] also evaluates from left to right:

  1. 赋值表达式 y = [ f(), x = g() ] 开始计算。
    1. 该赋值左侧的 y 计算结果为对名为 y 的变量的引用。
    2. 内部数组文字 [ f(), x = g() ] 开始计算。
      1. 函数调用 f() 将 "F!" 打印到控制台,然后计算结果为数字 2
      2. 赋值表达式 x = g() 开始计算。
        1. 该赋值左侧的 x 计算结果为对名为 x 的变量的引用。
        2. 函数调用 g() 将 "G!" 打印到控制台,然后计算结果为数字 3
        3. g()3 结果被分配给 x
      3. 赋值表达式 x = g() 现已完成求值;其结果是 x 的新值,即 33 结果成为内部数组文字中的下一个元素(在 f() 中的 2 之后)。
    3. 内部数组文字 [ f(), x = g() ] 现已完成评估;其结果是一个具有两个值的数组:[ 2, 3 ]
    4. [ 2, 3 ] 数组现在分配给 y
  2. 赋值表达式 y = [ f(), x = g() ] 现已完成求值;它的结果是 y 的新值 - 恰好是 [ 2, 3 ]x 现在分配给 3y 现在分配给 [ 2, 3 ],控制台先打印 "F!",然后打印 "G!"。

评价例 3

¥Evaluation example 3

x[f()] = g() 也从左到右评估。(此示例假设 x 已分配给某个对象。有关对象的更多信息,请阅读 使用对象。)

¥x[f()] = g() also evaluates from left to right. (This example assumes that x is already assigned to some object. For more information about objects, read Working with Objects.)

  1. 赋值表达式 x[f()] = g() 开始计算。
    1. 此作业左侧的 x[f()] 属性访问开始求值。
      1. 此属性访问中的 x 计算为对名为 x 的变量的引用。
      2. 然后函数调用 f() 将 "F!" 打印到控制台,然后计算结果为数字 2
    2. 此作业的 x[f()] 属性访问现已完成评估;它的结果是一个变量属性引用:x[2]
    3. 然后函数调用 g() 将 "G!" 打印到控制台,然后计算结果为数字 3
    4. 3 现在已分配给 x[2]。(只有将 x 分配给 object 时,此步骤才会成功。)
  2. 赋值表达式 x[f()] = g() 现已完成求值;它的结果是 x[2] 的新值 - 恰好是 3x[2] 现在已分配给 3,并且控制台已打印 "F!",然后打印 "G!"。

避免赋值链

¥Avoid assignment chains

在其他表达式中链接赋值或嵌套赋值可能会导致令人惊讶的行为。为此,不鼓励在同一个语句中进行链接赋值.

¥Chaining assignments or nesting assignments in other expressions can result in surprising behavior. For this reason, chaining assignments in the same statement is discouraged.

特别是,将变量链放入 constletvar 语句中通常不起作用。只有最外面/最左边的变量会被声明;赋值链中的其他变量不是由 const/let/var 语句声明的。例如:

¥In particular, putting a variable chain in a const, let, or var statement often does not work. Only the outermost/leftmost variable would get declared; other variables within the assignment chain are not declared by the const/let/var statement. For example:

js
const z = y = x = f();

该语句看似声明了变量 xyz。然而,它实际上只声明了变量 zyx 要么是对不存在变量(在 严格模式 中)的无效引用,要么更糟糕的是,会为 草率模式 中的 xy 隐式创建 全局变量

¥This statement seemingly declares the variables x, y, and z. However, it only actually declares the variable z. y and x are either invalid references to nonexistent variables (in strict mode) or, worse, would implicitly create global variables for x and y in sloppy mode.

比较运算符

¥Comparison operators

比较运算符比较其操作数,并根据比较是否为真返回逻辑值。操作数可以是数字、字符串、逻辑值或 object 值。使用 Unicode 值根据标准词典顺序比较字符串。在大多数情况下,如果两个操作数的类型不同,JavaScript 会尝试将它们转换为适当的类型以进行比较。此行为通常会导致对操作数进行数字比较。比较中类型转换的唯一例外涉及 ===!== 运算符,它们执行严格的相等和不等比较。在检查相等性之前,这些运算符不会尝试将操作数转换为兼容类型。下表描述了此示例代码中的比较运算符:

¥A comparison operator compares its operands and returns a logical value based on whether the comparison is true. The operands can be numerical, string, logical, or object values. Strings are compared based on standard lexicographical ordering, using Unicode values. In most cases, if the two operands are not of the same type, JavaScript attempts to convert them to an appropriate type for the comparison. This behavior generally results in comparing the operands numerically. The sole exceptions to type conversion within comparisons involve the === and !== operators, which perform strict equality and inequality comparisons. These operators do not attempt to convert the operands to compatible types before checking equality. The following table describes the comparison operators in terms of this sample code:

js
const var1 = 3;
const var2 = 4;
Comparison operators
运算符 描述 返回 true 的示例
平等的 (==) 如果操作数相等,则返回 true XSPACE3 == var1

"3" == var1

XSPACE3 == '3'
不等于 (!=) 如果操作数不相等,则返回 true var1 != 4
var2 != "3"
严格等于 (===) 如果操作数相等且类型相同,则返回 true。另请参见 Object.isJS 中的相同性 XSPACE3 === var1
严格不等于 (!==) 如果操作数类型相同但不相等,或者类型不同,则返回 true var1 !== "3"
XSPACE3 !== '3'
比...更棒 (>) 如果左操作数大于右操作数,则返回 true var2 > var1
"12" > 2
大于或等于 (>=) 如果左操作数大于或等于右操作数,则返回 true var2 >= var1
var1 >= 3
少于 (<) 如果左操作数小于右操作数,则返回 true var1 < var2
"2" < 12
小于或等于 (<=) 如果左操作数小于或等于右操作数,则返回 true var1 <= var2
var2 <= 5

注意:=> 不是比较运算符,而是 箭头函数 的符号。

¥Note: => is not a comparison operator but rather is the notation for Arrow functions.

算术运算符

¥Arithmetic operators

算术运算符将数值(文字或变量)作为操作数并返回单个数值。标准算术运算符是加法 (+)、减法 (-)、乘法 (*) 和除法 (/)。当与浮点数一起使用时,这些运算符的工作方式与大多数其他编程语言中的工作方式相同(特别是,请注意除以零会产生 Infinity)。例如:

¥An arithmetic operator takes numerical values (either literals or variables) as their operands and returns a single numerical value. The standard arithmetic operators are addition (+), subtraction (-), multiplication (*), and division (/). These operators work as they do in most other programming languages when used with floating point numbers (in particular, note that division by zero produces Infinity). For example:

js
1 / 2; // 0.5
1 / 2 === 1.0 / 2.0; // this is true

除了标准算术运算(+-*/)之外,JavaScript 还提供了下表列出的算术运算符:

¥In addition to the standard arithmetic operations (+, -, *, /), JavaScript provides the arithmetic operators listed in the following table:

Arithmetic operators
运算符 描述 示例
(%) 二元运算符。返回两个操作数相除的整数余数。 12% 5 返回 2。
增量 (++) 一元运算符。向其操作数加一。如果用作前缀运算符(++x),则返回其操作数加一后的值;如果用作后缀运算符 (x++),则在加一之前返回其操作数的值。 如果 x 为 3,则 ++xx 设置为 4 并返回 4,而 x++ 返回 3,然后将 x 设置为 4。
递减 (--) 一元运算符。从其操作数中减一。返回值类似于增量运算符的返回值。 如果 x 为 3,则 --xx 设置为 2 并返回 2,而 x-- 返回 3,然后将 x 设置为 2。
一元否定 (-) 一元运算符。返回其操作数的负数。 如果 x 为 3,则 -x 返回 -3。
一元加 (+) 一元运算符。尝试 将操作数转换为数字(如果尚未)。

+"3" 返回 XSPACE3

+true 返回 XSPACE1

求幂运算符 (**) 计算 baseexponent 次方,即 base^exponent XSPACE2 ** 3 返回 XSPACE8
XSPACE10 ** -1 返回 XSPACE0.1

按位运算符

¥Bitwise operators

按位运算符将其操作数视为一组 32 位(零和一),而不是十进制、十六进制或八进制数。例如,十进制数字 9 的二进制表示形式为 1001。位运算符对此类二进制表示形式执行运算,但它们返回标准 JavaScript 数值。

¥A bitwise operator treats their operands as a set of 32 bits (zeros and ones), rather than as decimal, hexadecimal, or octal numbers. For example, the decimal number nine has a binary representation of 1001. Bitwise operators perform their operations on such binary representations, but they return standard JavaScript numerical values.

下表总结了 JavaScript 的按位运算符。

¥The following table summarizes JavaScript's bitwise operators.

运算符 用法 描述
按位与 a & b 在两个操作数的对应位均为 1 的每个位位置返回 1。
按位或 a | b 在两个操作数的相应位均为零的每个位位置返回零。
按位异或 a ^ b 在对应位相同的每个位位置返回零。[在对应位不同的每个位位置返回 1。]
按位非 ~ a 反转其操作数的位。
左移 a << b 将二进制表示形式的 a 向左移动 b 位,从右侧移入零。
符号传播右移 a >> b 将二进制表示形式的 a 右移 b 位,丢弃移出的位。
零填充右移 a >>> b 将二进制表示形式的 a 向右移动 b 位,丢弃移出的位,并从左侧移入零。

按位逻辑运算符

¥Bitwise logical operators

从概念上讲,按位逻辑运算符的工作原理如下:

¥Conceptually, the bitwise logical operators work as follows:

  • 操作数被转换为三十二位整数并由一系列位(零和一)表示。超过 32 位的数字将丢弃其最高有效位。例如,以下超过 32 位的整数将被转换为 32 位整数:
    Before: 1110 0110 1111 1010 0000 0000 0000 0110 0000 0000 0001
    After:                 1010 0000 0000 0000 0110 0000 0000 0001
    
  • 第一个操作数中的每个位都与第二个操作数中的相应位配对:第一位到第一位,第二位到第二位,依此类推。
  • 该运算符应用于每对位,并按位构造结果。

例如,九的二进制表示为 1001,十五的二进制表示为 1111。因此,当对这些值应用按位运算符时,结果如下:

¥For example, the binary representation of nine is 1001, and the binary representation of fifteen is 1111. So, when the bitwise operators are applied to these values, the results are as follows:

表达 结果 二进制描述
15 & 9 9 1111 & 1001 = 1001
15 | 9 15 1111 | 1001 = 1111
15 ^ 9 6 1111 ^ 1001 = 0110
~15 -16 ~ 0000 0000 … 0000 1111 = 1111 1111 … 1111 0000
~9 -10 ~ 0000 0000 … 0000 1001 = 1111 1111 … 1111 0110

请注意,所有 32 位均使用按位 NOT 运算符进行反转,并且最高有效(最左边)位设置为 1 的值表示负数(二进制补码表示形式)。~x 的计算结果与 -x - 1 的计算结果相同。

¥Note that all 32 bits are inverted using the Bitwise NOT operator, and that values with the most significant (left-most) bit set to 1 represent negative numbers (two's-complement representation). ~x evaluates to the same value that -x - 1 evaluates to.

按位移位运算符

¥Bitwise shift operators

按位移位运算符采用两个操作数:第一个是要移位的量,第二个指定第一个操作数要移位的位数。移位操作的方向由所使用的操作器控制。

¥The bitwise shift operators take two operands: the first is a quantity to be shifted, and the second specifies the number of bit positions by which the first operand is to be shifted. The direction of the shift operation is controlled by the operator used.

移位运算符将其操作数转换为 32 位整数并返回 NumberBigInt 类型的结果:具体来说,如果左操作数的类型是 BigInt,则返回 BigInt;否则,他们返回 Number

¥Shift operators convert their operands to thirty-two-bit integers and return a result of either type Number or BigInt: specifically, if the type of the left operand is BigInt, they return BigInt; otherwise, they return Number.

下表列出了移位运算符。

¥The shift operators are listed in the following table.

Bitwise shift operators
运算符 描述 示例
左移
(<<)
该运算符将第一个操作数向左移动指定的位数。向左移出的多余位将被丢弃。零位从右侧移入。 XSPACE9<<2 得到 36,因为 1001 左移 2 位变成 100100,即 36。
符号传播右移 (>>) 该运算符将第一个操作数向右移动指定的位数。向右移出的多余位将被丢弃。最左边位的副本从左侧移入。 XSPACE9>>XSPACE2 产生 2,因为 1001 右移 2 位变为 10,即 2。同样, -9>>XSPACE2 产生 -3,因为符号被保留。
零填充右移 (>>>) 该运算符将第一个操作数向右移动指定的位数。向右移出的多余位将被丢弃。零位从左侧移入。 XSPACE19>>>XSPACE2 产生 4,因为 10011 右移 2 位变为 100,即 4。对于非负数,零填充右移和符号传播右移产生相同的结果。

逻辑运算符

¥Logical operators

逻辑运算符通常与布尔(逻辑)值一起使用;当它们是时,它们返回一个布尔值。但是,&&|| 运算符实际上返回指定操作数之一的值,因此如果这些运算符与非布尔值一起使用,它们可能会返回非布尔值。下表描述了逻辑运算符。

¥Logical operators are typically used with Boolean (logical) values; when they are, they return a Boolean value. However, the && and || operators actually return the value of one of the specified operands, so if these operators are used with non-Boolean values, they may return a non-Boolean value. The logical operators are described in the following table.

Logical operators
运算符 用法 描述
逻辑与 (&&) expr1 && expr2 如果可以转换为 false,则返回 expr1;否则,返回 expr2。因此,当与布尔值一起使用时,如果两个操作数都为 true,则 && 返回 true;否则,返回 false
逻辑或 (||) expr1 || expr2 如果可以转换为 true,则返回 expr1;否则,返回 expr2。因此,当与布尔值一起使用时,如果任一操作数为 true,则 || 返回 true;如果两者都为 false,则返回 false
逻辑非 (!) !expr 如果单个操作数可以转换为 true,则返回 false;否则,返回 true

可转换为 false 的表达式示例包括计算结果为 null、0、NaN、空字符串 ("") 或未定义的表达式。

¥Examples of expressions that can be converted to false are those that evaluate to null, 0, NaN, the empty string (""), or undefined.

以下代码显示了 &&(逻辑 AND)运算符的示例。

¥The following code shows examples of the && (logical AND) operator.

js
const a1 = true && true; // t && t returns true
const a2 = true && false; // t && f returns false
const a3 = false && true; // f && t returns false
const a4 = false && 3 === 4; // f && f returns false
const a5 = "Cat" && "Dog"; // t && t returns Dog
const a6 = false && "Cat"; // f && t returns false
const a7 = "Cat" && false; // t && f returns false

以下代码显示了 || 的示例 (逻辑或)运算符。

¥The following code shows examples of the || (logical OR) operator.

js
const o1 = true || true; // t || t returns true
const o2 = false || true; // f || t returns true
const o3 = true || false; // t || f returns true
const o4 = false || 3 === 4; // f || f returns false
const o5 = "Cat" || "Dog"; // t || t returns Cat
const o6 = false || "Cat"; // f || t returns Cat
const o7 = "Cat" || false; // t || f returns Cat

以下代码显示了 ! (逻辑非)运算符。

¥The following code shows examples of the ! (logical NOT) operator.

js
const n1 = !true; // !t returns false
const n2 = !false; // !f returns true
const n3 = !"Cat"; // !t returns false

短路评估

¥Short-circuit evaluation

由于逻辑表达式是从左到右计算的,因此使用以下规则测试可能的 "short-circuit" 计算:

¥As logical expressions are evaluated left to right, they are tested for possible "short-circuit" evaluation using the following rules:

  • false && anything 短路评估为假。
  • true || anything 短路评估为真。

逻辑规则保证这些评估总是正确的。请注意,上述表达式的任何部分都不会被求值,因此这样做的任何副作用都不会生效。

¥The rules of logic guarantee that these evaluations are always correct. Note that the anything part of the above expressions is not evaluated, so any side effects of doing so do not take effect.

请注意,对于第二种情况,在现代代码中,你可以使用与 || 类似的 空合并运算符 (??),但当第一个表达式为“nullish”(即 nullundefined)时,它仅返回第二个表达式。因此,当 ''0 之类的值也是第一个表达式的有效值时,提供默认值是更好的选择。

¥Note that for the second case, in modern code you can use the Nullish coalescing operator (??) that works like ||, but it only returns the second expression, when the first one is "nullish", i.e. null or undefined. It is thus the better alternative to provide defaults, when values like '' or 0 are valid values for the first expression, too.

BigInt 运算符

¥BigInt operators

大多数可以在数字之间使用的运算符也可以在 BigInt 值之间使用。

¥Most operators that can be used between numbers can be used between BigInt values as well.

js
// BigInt addition
const a = 1n + 2n; // 3n
// Division with BigInts round towards zero
const b = 1n / 2n; // 0n
// Bitwise operations with BigInts do not truncate either side
const c = 40000000000000000n >> 2n; // 10000000000000000n

一个例外是 无符号右移 (>>>),它没有为 BigInt 值定义。这是因为 BigInt 没有固定宽度,因此从技术上讲它没有 "最高位"。

¥One exception is unsigned right shift (>>>), which is not defined for BigInt values. This is because a BigInt does not have a fixed width, so technically it does not have a "highest bit".

js
const d = 8n >>> 2n; // TypeError: BigInts have no unsigned right shift, use >> instead

BigInt 和数字不能相互替换 - 不能在计算中混合使用它们。

¥BigInts and numbers are not mutually replaceable — you cannot mix them in calculations.

js
const a = 1n + 2; // TypeError: Cannot mix BigInt and other types

这是因为 BigInt 既不是数字的子集也不是数字的超集。BigInt 在表示大整数时比数字具有更高的精度,但不能表示小数,因此任何一方的隐式转换都可能会丢失精度。使用显式转换来表明你希望该运算是数字运算还是 BigInt 运算。

¥This is because BigInt is neither a subset nor a superset of numbers. BigInts have higher precision than numbers when representing large integers, but cannot represent decimals, so implicit conversion on either side might lose precision. Use explicit conversion to signal whether you wish the operation to be a number operation or a BigInt one.

js
const a = Number(1n) + 2; // 3
const b = 1n + BigInt(2); // 3n

你可以将 BigInt 与数字进行比较。

¥You can compare BigInts with numbers.

js
const a = 1n > 2; // false
const b = 3 > 2n; // true

字符串运算符

¥String operators

除了可用于字符串值的比较运算符之外,连接运算符 (+) 将两个字符串值连接在一起,返回另一个字符串,该字符串是两个操作数字符串的并集。

¥In addition to the comparison operators, which can be used on string values, the concatenation operator (+) concatenates two string values together, returning another string that is the union of the two operand strings.

例如,

¥For example,

js
console.log("my " + "string"); // console logs the string "my string".

速记赋值运算符 += 也可用于连接字符串。

¥The shorthand assignment operator += can also be used to concatenate strings.

例如,

¥For example,

js
let mystring = "alpha";
mystring += "bet"; // evaluates to "alphabet" and assigns this value to mystring.

条件(三元)运算符

¥Conditional (ternary) operator

条件运算符 是唯一采用三个操作数的 JavaScript 运算符。根据条件,运算符可以具有两个值之一。语法是:

¥The conditional operator is the only JavaScript operator that takes three operands. The operator can have one of two values based on a condition. The syntax is:

js
condition ? val1 : val2

如果 condition 为真,则运算符的值为 val1。否则其值为 val2。你可以在任何需要使用标准运算符的地方使用条件运算符。

¥If condition is true, the operator has the value of val1. Otherwise it has the value of val2. You can use the conditional operator anywhere you would use a standard operator.

例如,

¥For example,

js
const status = age >= 18 ? "adult" : "minor";

如果 age 为 18 或更大,则此语句将值 "adult" 赋给变量 status。否则,它将值 "minor" 分配给 status

¥This statement assigns the value "adult" to the variable status if age is eighteen or more. Otherwise, it assigns the value "minor" to status.

逗号运算符

¥Comma operator

逗号运算符 (,) 计算其两个操作数并返回最后一个操作数的值。该运算符主要在 for 循环内使用,以允许每次通过循环更新多个变量。当没有必要时,在其他地方使用它被认为是不好的风格。通常可以而且应该使用两个单独的语句来代替。

¥The comma operator (,) evaluates both of its operands and returns the value of the last operand. This operator is primarily used inside a for loop, to allow multiple variables to be updated each time through the loop. It is regarded bad style to use it elsewhere, when it is not necessary. Often two separate statements can and should be used instead.

例如,如果 a 是一个一边有 10 个元素的二维数组,则以下代码使用逗号运算符一次更新两个变量。该代码打印数组中对角线元素的值:

¥For example, if a is a 2-dimensional array with 10 elements on a side, the following code uses the comma operator to update two variables at once. The code prints the values of the diagonal elements in the array:

js
const x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
const a = [x, x, x, x, x];

for (let i = 0, j = 9; i <= j; i++, j--) {
  //                              ^
  console.log(`a[${i}][${j}]= ${a[i][j]}`);
}

一元运算符

¥Unary operators

一元运算是只有一个操作数的运算。

¥A unary operation is an operation with only one operand.

delete

delete 运算符删除对象的属性。语法是:

¥The delete operator deletes an object's property. The syntax is:

js
delete object.property;
delete object[propertyKey];
delete objectName[index];

其中 object 是对象的名称,property 是现有属性,propertyKey 是引用现有属性的字符串或符号。

¥where object is the name of an object, property is an existing property, and propertyKey is a string or symbol referring to an existing property.

如果 delete 运算符成功,它将从对象中删除该属性。之后尝试访问它会产生 undefined。如果操作可行,则 delete 运算符返回 true;如果操作不可能,则返回 false

¥If the delete operator succeeds, it removes the property from the object. Trying to access it afterwards will yield undefined. The delete operator returns true if the operation is possible; it returns false if the operation is not possible.

js
delete Math.PI; // returns false (cannot delete non-configurable properties)

const myObj = { h: 4 };
delete myObj.h; // returns true (can delete user-defined properties)

删除数组元素

¥Deleting array elements

由于数组只是对象,因此从技术上讲可以从其中获取 delete 个元素。然而,这被认为是一种不好的做法 - 尽量避免。删除数组属性时,数组长度不受影响,并且其他元素不会重新索引。要实现该行为,最好用值 undefined 覆盖该元素。要实际操作数组,请使用各种数组方法,例如 splice

¥Since arrays are just objects, it's technically possible to delete elements from them. This is, however, regarded as a bad practice — try to avoid it. When you delete an array property, the array length is not affected and other elements are not re-indexed. To achieve that behavior, it is much better to just overwrite the element with the value undefined. To actually manipulate the array, use the various array methods such as splice.

typeof

typeof 运算符 返回一个字符串,指示未计算的操作数的类型。operand 是要返回其类型的字符串、变量、关键字或对象。括号是可选的。

¥The typeof operator returns a string indicating the type of the unevaluated operand. operand is the string, variable, keyword, or object for which the type is to be returned. The parentheses are optional.

假设你定义以下变量:

¥Suppose you define the following variables:

js
const myFun = new Function("5 + 2");
const shape = "round";
const size = 1;
const foo = ["Apple", "Mango", "Orange"];
const today = new Date();

typeof 运算符返回这些变量的以下结果:

¥The typeof operator returns the following results for these variables:

js
typeof myFun; // returns "function"
typeof shape; // returns "string"
typeof size; // returns "number"
typeof foo; // returns "object"
typeof today; // returns "object"
typeof doesntExist; // returns "undefined"

对于关键字 truenulltypeof 运算符返回以下结果:

¥For the keywords true and null, the typeof operator returns the following results:

js
typeof true; // returns "boolean"
typeof null; // returns "object"

对于数字或字符串,typeof 运算符返回以下结果:

¥For a number or string, the typeof operator returns the following results:

js
typeof 62; // returns "number"
typeof "Hello world"; // returns "string"

对于属性值,typeof 运算符返回属性包含的值的类型:

¥For property values, the typeof operator returns the type of value the property contains:

js
typeof document.lastModified; // returns "string"
typeof window.length; // returns "number"
typeof Math.LN2; // returns "number"

对于方法和函数,typeof 运算符返回结果如下:

¥For methods and functions, the typeof operator returns results as follows:

js
typeof blur; // returns "function"
typeof eval; // returns "function"
typeof parseInt; // returns "function"
typeof shape.split; // returns "function"

对于预定义对象,typeof 运算符返回结果如下:

¥For predefined objects, the typeof operator returns results as follows:

js
typeof Date; // returns "function"
typeof Function; // returns "function"
typeof Math; // returns "object"
typeof Option; // returns "function"
typeof String; // returns "function"

void

void 运算符 指定要计算但不返回值的表达式。expression 是要计算的 JavaScript 表达式。表达式周围的括号是可选的,但使用它们以避免优先级问题是一种很好的风格。

¥The void operator specifies an expression to be evaluated without returning a value. expression is a JavaScript expression to evaluate. The parentheses surrounding the expression are optional, but it is good style to use them to avoid precedence issues.

关系运算符

¥Relational operators

关系运算符比较其操作数,并根据比较是否为真返回布尔值。

¥A relational operator compares its operands and returns a Boolean value based on whether the comparison is true.

in

如果指定属性位于指定对象中,则 in 运算符 返回 true。语法是:

¥The in operator returns true if the specified property is in the specified object. The syntax is:

js
propNameOrNumber in objectName

其中 propNameOrNumber 是表示属性名称或数组索引的字符串、数字或符号表达式,objectName 是对象的名称。

¥where propNameOrNumber is a string, numeric, or symbol expression representing a property name or array index, and objectName is the name of an object.

以下示例显示了 in 运算符的一些用法。

¥The following examples show some uses of the in operator.

js
// Arrays
const trees = ["redwood", "bay", "cedar", "oak", "maple"];
0 in trees; // returns true
3 in trees; // returns true
6 in trees; // returns false
"bay" in trees; // returns false
// (you must specify the index number, not the value at that index)
"length" in trees; // returns true (length is an Array property)

// built-in objects
"PI" in Math; // returns true
const myString = new String("coral");
"length" in myString; // returns true

// Custom objects
const mycar = { make: "Honda", model: "Accord", year: 1998 };
"make" in mycar; // returns true
"model" in mycar; // returns true

instanceof

如果指定对象属于指定对象类型,则 instanceof 运算符 返回 true。语法是:

¥The instanceof operator returns true if the specified object is of the specified object type. The syntax is:

js
objectName instanceof objectType

其中 objectName 是要与 objectType 进行比较的对象的名称,objectType 是对象类型,例如 DateArray

¥where objectName is the name of the object to compare to objectType, and objectType is an object type, such as Date or Array.

当需要在运行时确认对象的类型时,请使用 instanceof。例如,当捕获异常时,你可以根据抛出的异常类型分支到不同的异常处理代码。

¥Use instanceof when you need to confirm the type of an object at runtime. For example, when catching exceptions, you can branch to different exception-handling code depending on the type of exception thrown.

例如,下面的代码使用 instanceof 来判断 theDay 是否是 Date 对象。由于 theDayDate 对象,因此执行 if 语句中的语句。

¥For example, the following code uses instanceof to determine whether theDay is a Date object. Because theDay is a Date object, the statements in the if statement execute.

js
const theDay = new Date(1995, 12, 17);
if (theDay instanceof Date) {
  // statements to execute
}

基本表达

¥Basic expressions

所有运算符最终都会对一个或多个基本表达式进行运算。这些基本表达式包括 identifiersliterals,但还有其他几种。下面简要介绍它们,它们的语义在各自的参考部分中详细描述。

¥All operators eventually operate on one or more basic expressions. These basic expressions include identifiers and literals, but there are a few other kinds as well. They are briefly introduced below, and their semantics are described in detail in their respective reference sections.

this

使用 this 关键字 来引用当前对象。一般来说,this 指的是方法中的调用对象。将 this 与点或括号符号一起使用:

¥Use the this keyword to refer to the current object. In general, this refers to the calling object in a method. Use this either with the dot or the bracket notation:

js
this["propertyName"];
this.propertyName;

假设一个名为 validate 的函数在给定对象以及高值和低值的情况下验证对象的 value 属性:

¥Suppose a function called validate validates an object's value property, given the object and the high and low values:

js
function validate(obj, lowval, hival) {
  if (obj.value < lowval || obj.value > hival) {
    console.log("Invalid Value!");
  }
}

你可以在每个表单元素的 onChange 事件处理程序中调用 validate,使用 this 将其传递给表单元素,如下例所示:

¥You could call validate in each form element's onChange event handler, using this to pass it to the form element, as in the following example:

html
<p>Enter a number between 18 and 99:</p>
<input type="text" name="age" size="3" onChange="validate(this, 18, 99);" />

分组运算符

¥Grouping operator

分组运算符 ( ) 控制表达式中求值的优先级。例如,你可以先覆盖乘法和除法,然后覆盖加法和减法,以首先计算加法。

¥The grouping operator ( ) controls the precedence of evaluation in expressions. For example, you can override multiplication and division first, then addition and subtraction to evaluate addition first.

js
const a = 1;
const b = 2;
const c = 3;

// default precedence
a + b * c     // 7
// evaluated by default like this
a + (b * c)   // 7

// now overriding precedence
// addition before multiplication
(a + b) * c   // 9

// which is equivalent to
a * c + b * c // 9

new

你可以使用 new 运算符 创建用户定义对象类型或内置对象类型之一的实例。使用 new 如下:

¥You can use the new operator to create an instance of a user-defined object type or of one of the built-in object types. Use new as follows:

js
const objectName = new ObjectType(param1, param2, /* …, */ paramN);

super

super 关键字 用于调用对象父对象上的函数。例如,使用 classes 调用父构造函数很有用。

¥The super keyword is used to call functions on an object's parent. It is useful with classes to call the parent constructor, for example.

js
super(args); // calls the parent constructor.
super.functionOnParent(args);