表达式和运算符

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

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

表达式 x = 7 是第一种类型的示例。此表达式使用 = 运算符将值 7 分配给变量 x。表达式本身求值为 7

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

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

这些运算符连接由更高优先级的运算符或基本表达式之一形成的操作数。运算符和表达式的完整详细列表也可在参考中找到。

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

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

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

JavaScript 既有二元运算符,也有一元运算符,还有一个特殊的三元运算符,即条件运算符。二元运算符需要两个操作数,一个在运算符之前,一个在运算符之后

operand1 operator operand2

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

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

operator operand
operand operator

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

赋值运算符

赋值运算符根据其右操作数的值将其左操作数赋予一个值。简单的赋值运算符是等号 (=),它将其右操作数的值赋予其左操作数。也就是说,x = f() 是一个赋值表达式,它将 f() 的值赋予 x

还有一些复合赋值运算符,它们是以下表格中列出的运算符的简写

名称 简写运算符 含义
赋值 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())

分配给属性

如果表达式求值为对象,则赋值表达式的左侧可以对该表达式的属性进行赋值。例如

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 }.

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

如果表达式没有求值为对象,则对该表达式属性的赋值不会进行赋值

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

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

严格模式下,上面的代码会抛出错误,因为不能将属性分配给原始值。

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

解构

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

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

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

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

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

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

评估和嵌套

通常,赋值用于变量声明中(即,使用constletvar)或作为独立语句。

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())会求值为结果值。虽然此结果值通常不会使用,但它随后可以被另一个表达式使用。

链式赋值或在其他表达式中嵌套赋值可能会导致意外的行为。出于这个原因,一些 JavaScript 样式指南不建议链式赋值或嵌套赋值。尽管如此,链式赋值和嵌套赋值有时可能会发生,因此了解它们的工作原理非常重要。

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

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(),依此类推。

在逻辑赋值的情况下,x &&= f()x ||= f()x ??= f(),返回值是逻辑运算符本身的返回值,而不是赋值后的返回值,所以分别是x && f()x || f()x ?? f()

在没有括号或其他分组运算符(如数组字面量)的情况下链接这些表达式时,赋值表达式从右到左分组(它们是右结合),但它们从左到右求值

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

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

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

考虑以下三个示例

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

评估示例 1

y = x = f()等价于y = (x = f()),因为赋值运算符=右结合的。但是,它从左到右求值

  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

y = [ f(), x = g() ]也从左到右求值

  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的新值,即3。该3结果成为内部数组字面量中的下一个元素(在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

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

  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被赋值给一个对象时,此步骤才会成功。)
  2. 赋值表达式x[f()] = g()现在已完成求值;其结果是x[2]的新值,即3x[2]现在被赋值为3,控制台打印了“F!”然后是“G!”。

避免赋值链

链式赋值或在其他表达式中嵌套赋值可能会导致意外的行为。出于这个原因,不建议在同一语句中进行链式赋值

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

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

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

比较运算符

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

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

"3" == var1

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

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

算术运算符

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

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

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

算术运算符
运算符 描述 示例
取余 (%) 二元运算符。返回两个操作数相除的整数余数。 12 % 5 返回 2。
自增 (++) 一元运算符。将其操作数加 1。如果用作前缀运算符 (++x),则在加 1 后返回其操作数的值;如果用作后缀运算符 (x++),则在加 1 之前返回其操作数的值。 如果x为 3,则++xx设置为 4 并返回 4,而x++返回 3,然后才将x设置为 4。
自减 (--) 一元运算符。将其操作数减 1。返回值类似于自增运算符。 如果x为 3,则--xx设置为 2 并返回 2,而x--返回 3,然后才将x设置为 2。

一元否定运算符 (-) 一元运算符。返回其操作数的负值。 如果 x 为 3,则 -x 返回 -3。
一元正号运算符 (+) 一元运算符。尝试将操作数转换为数字,如果它还不是数字。

+"3" 返回 3

+true 返回 1

指数运算符 (**) 计算 底数指数 次幂,即 底数^指数 2 ** 3 返回 8
10 ** -1 返回 0.1

按位运算符

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

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

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

位逻辑运算符

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

  • 操作数被转换为 32 位整数并用一系列位(零和一)表示。超过 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。因此,当位运算符应用于这些值时,结果如下

表达式 结果 二进制描述
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 位,并且最高有效位(最左边)设置为 1 的值表示负数(二进制补码表示法)。~x 的计算结果与 -x - 1 的计算结果相同。

位移运算符

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

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

下表列出了移位运算符。

位移运算符
运算符 描述 示例
左移
(<<)
此运算符将第一个操作数向左移动指定的位数。向左移出的多余位将被丢弃。从右边移入零位。 9<<2 产生 36,因为 1001 向左移动 2 位变为 100100,即 36。
带符号右移 (>>) 此运算符将第一个操作数向右移动指定的位数。向右移出的多余位将被丢弃。最左边的位的副本从左边移入。 9>>2 产生 2,因为 1001 向右移动 2 位变为 10,即 2。同样,-9>>2 产生 -3,因为符号被保留。
无符号右移 (>>>) 此运算符将第一个操作数向右移动指定的位数。向右移出的多余位将被丢弃。从左边移入零位。 19>>>2 产生 4,因为 10011 向右移动 2 位变为 100,即 4。对于非负数,无符号右移和带符号右移产生相同的结果。

逻辑运算符

逻辑运算符通常与布尔(逻辑)值一起使用;当它们这样做时,它们会返回一个布尔值。但是,&&||?? 运算符实际上返回指定操作数之一的值,因此如果这些运算符与非布尔值一起使用,则它们可能会返回非布尔值。因此,更准确地将它们称为“值选择运算符”。下表描述了逻辑运算符。

逻辑运算符
运算符 用法 描述
逻辑与 (&&) expr1 && expr2 如果 expr1 可以转换为 false,则返回 expr1;否则,返回 expr2。因此,当与布尔值一起使用时,&& 如果两个操作数都为真,则返回 true;否则,返回 false
逻辑或 (||) expr1 || expr2 如果 expr1 可以转换为 true,则返回 expr1;否则,返回 expr2。因此,当与布尔值一起使用时,|| 如果任一操作数为真,则返回 true;如果两者都为假,则返回 false
空值合并运算符 (??) expr1 ?? expr2 如果 expr1 不是 null 也不 undefined,则返回 expr1;否则,返回 expr2
逻辑非 (!) !expr 如果其单个操作数可以转换为 true,则返回 false;否则,返回 true

可以转换为 false 的表达式的示例包括那些计算结果为 null00nNaN、空字符串 ("") 或 undefined 的表达式。

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

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

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

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

以下代码显示了 ??(空值合并)运算符的示例。

js
const n1 = null ?? 1; // 1
const n2 = undefined ?? 2; // 2
const n3 = false ?? 3; // false
const n4 = 0 ?? 4; // 0

请注意 ?? 如何像 || 一样工作,但它仅在第一个表达式为“空值”(即 nullundefined)时才返回第二个表达式。?? 是为可能为 nullundefined 的值设置默认值的一个更好的替代方案,尤其是在 ''0 等值为有效值并且不应应用默认值时。

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

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

短路求值

由于逻辑表达式是从左到右求值的,因此它们使用以下规则测试可能的“短路”求值

  • falsy && anything 将短路求值为假值。
  • truthy || anything 将短路求值为真值。
  • nonNullish ?? anything 将短路求值为非空值。

逻辑规则保证这些求值始终是正确的。请注意,上述表达式的 anything 部分未求值,因此执行此操作的任何副作用都不会生效。

BigInt 运算符

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

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 没有固定的宽度,因此从技术上讲它没有“最高位”。

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

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

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

这是因为 BigInt 既不是数字的子集也不是超集。在表示大整数时,BigInt 比数字具有更高的精度,但不能表示小数,因此任一侧的隐式转换可能会丢失精度。使用显式转换来指示您希望操作是数字操作还是 BigInt 操作。

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

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

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

字符串运算符

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

例如,

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

简写赋值运算符 += 也可以用于连接字符串。

例如,

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

条件 (三元) 运算符

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

js
condition ? val1 : val2

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

例如,

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

此语句如果 age 大于或等于 18,则将值“adult”分配给变量 status。否则,它将值“minor”分配给 status

逗号运算符

逗号运算符 (,) 会计算其两个操作数并返回最后一个操作数的值。此运算符主要用于 for 循环中,以允许每次循环更新多个变量。在不需要的情况下,在其他地方使用它被认为是不好的风格。通常可以使用(也应该使用)两个单独的语句来代替。

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

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]}`);
}

一元运算符

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

delete

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

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

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

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

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)

删除数组元素

由于数组只是对象,所以从技术上讲,可以从数组中delete元素。然而,这被认为是一种不好的做法——尽量避免这样做。当您删除数组属性时,数组长度不会受到影响,其他元素也不会重新索引。为了实现这种行为,最好只是用值undefined覆盖该元素。要真正操作数组,请使用各种数组方法,例如splice

typeof

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

假设您定义了以下变量

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

对于这些变量,typeof运算符返回以下结果

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运算符返回以下结果

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

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

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

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

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

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

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

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

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 表达式。表达式周围的括号是可选的,但最好使用它们以避免优先级问题。

关系运算符

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

in

in运算符如果指定的属性在指定对象中,则返回true。语法如下:

js
propNameOrNumber in objectName

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

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

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。语法如下:

js
object instanceof objectType

其中object是要针对objectType测试的对象,objectType是表示类型的构造函数,例如DateArray

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

例如,以下代码使用instanceof来确定theDay是否为Date对象。因为theDayDate对象,所以if语句中的语句将执行。

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

基本表达式

所有运算符最终都会对一个或多个基本表达式进行运算。这些基本表达式包括标识符字面量,但也有一些其他类型。它们在下面进行了简要介绍,并且它们的语义将在各自的参考部分中详细描述。

this

使用this关键字来引用当前对象。通常,this在方法中引用调用对象。使用this与点或括号表示法一起使用

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

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

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

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

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

分组运算符

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

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

属性访问器

属性访问器语法使用点表示法或括号表示法获取对象上的属性值。

js
object.property;
object["property"];

使用对象指南更详细地介绍了对象属性。

可选链

可选链语法 (?.) 如果对象已定义且不为null,则对对象执行链式操作,否则短路操作并返回undefined。这允许您对可能为nullundefined的值进行操作,而不会导致TypeError

js
maybeObject?.property;
maybeObject?.[property];
maybeFunction?.();

new

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

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

super

super关键字用于在对象的父对象上调用函数。它与一起使用很有用,例如,用于调用父构造函数。

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