Python测开28期-偕行-JavaScript运算符

1、术语介绍

  • 操作数: 是运算符操作的项目。如果我们将运算符视为一种操作,那么操作数就是该操作应用于的对象。例如,在表达式5 + 3中,+是运算符(加法操作),而5和3是操作数,即要相加的数字。在JavaScript中,操作数可以是不同类型的,如数字、字符串、变量,甚至更复杂的表达式。

  • 强制类型转换: 是将一个值从一种原始类型转换为另一种原始类型的过程。例如,JavaScript可能会将数字更改为字符串,或者将非布尔值更改为布尔值。

    • JavaScript中的原始类型包括StringNumberBigIntBooleanundefinedSymbolnull
    • NaN:代表不是数字。它是Number类型的特殊值,表示无效或无法表示的数值。
  • 真值:是在布尔上下文中评估为true的值,而假值在布尔上下文中评估为false

    • 假值包括false0''nullundefinedNaNBigInt(0)

2、 算术运算符

算术运算符允许我们对值执行算术运算,并对数据进行转换。JavaScript中常用的算术运算符包括:

  • 加法(+
  • 减法(-
  • 乘法(*
  • 除法(/
  • 取模运算符(%),它返回除法操作的余数
  • 自增运算符(++),将值增加1
  • 自减运算符(--),将值减少1

(1)加法

加法运算符 执行两种不同的操作:数字相加字符串连接。在使用+ 运算符计算表达式时,JavaScript首先将两个操作数转换为原始值。完成此操作后,它会检查两个操作数的类型。

  • 如果一个操作数是字符串,则将另一个操作数也转换为字符串,然后连接这两个字符串;
'Hello, ' + 'World!' // Hello, World!
'The number is ' + 42 // 'The number is 42'
  • 如果两个操作数都是BigInts ,则执行BigInt 加法; 但如果一个操作数是BigInts ,另一个不是,JavaScript会抛出TypeError
const num1 = BigInt(12345678901234567890);
const num2 = BigInt(12345678901234567890);
num1 + num2 // 24691357802469134336n
num1 + 1 // Uncaught TypeError: Cannot mix BigInt and other types, use explicit conversions
  • 对于所有其他情况,两个操作数都将转换为数字,并执行数字相加;
10 + 20 // 30
10 + true // 11 — true会转换为值1
  • 请注意,JavaScript有一些奇怪的输出:
    • 在这种情况下,JavaScript试图将对象{ a: 1 } 转换为原始值,但它能做的就是将其转换为字符串[object Object] ,然后与数字1连接起来。
1 + { a: 1 } // '1[object Object]'

(2)减法

JavaScript中的减法运算符 在使用上很简单:用一个数字减去另一个数字。与加法运算符一样,它也适用于BigInt 类型。

  • 如果两个操作数是数字或可以转换为数字,JavaScript执行数字减法;
10 - 3 // 7
'100' - 30 // 70
  • 如果两个操作数都是BigInts ,JavaScript执行BigInt 减法;
const num1 = BigInt('9007199254740993');
const num2 = BigInt('3');
num1 - num2 // 9007199254740990n
  • 与加法运算符一样,当与非数字一起使用时,减法也可能产生意想不到的结果;
    • 例如,如果我们尝试减去无法转换为数字的内容,JavaScript将返回NaN ,表示“不是数字”:
10 - 'Jim' // NaN

(3)乘法

乘法运算符适用于数字和BigInts

  • 通常我们将对数字进行乘法运算:
10 * 5 // 50
  • 如果两个操作数都是BigInts ,则执行BigInt 乘法:
const num1 = 9007199254740993n;
num1 * 2n // 18014398509481986n
  • 与其他运算符一样,JavaScript尝试将非数字值转换为数字。如果无法这样做,它将返回NaN
'100' * 30 // 3000
10 * 'Jim' // NaN

(4)除法

除法运算符/ )与数字和BigInts 一起使用,方式与+-* 类似。它首先将两个操作数转换为数字。

  • 标准数值除法:
console.log(10/3) // 3.3333333333333335
console.log(10/2) // 5
console.log(10/'2')// 5
  • 处理BigInts 时,除法运算符的行为稍有不同。它执行除法并丢弃任何余数,从效果上来说是向零截断结果:
const num = 10n;
num / 3n // 3n,而不是3.333...n
  • 除以零的结果将产生Infinity ,除非是BigInt ,在这种情况下会引发RangeError

  • 如果我们尝试将数字除以无法转换为数字的值,JavaScript通常会返回NaN

(5) 模数(余数)

模数运算符 用于找到一个数除以另一个数(称为被除数除数 )后的余数。这个算术运算符适用于数字和BigInts

  • 当我们使用% 运算符时,JavaScript首先将操作数转换为数字:
10 % 3 // 1
'10' % 3 // 1
  • 这个运算符的一个常见用例是检查一个数是奇数还是偶数:
// 这里使用了一个箭头函数和稍后会介绍的三重等号运算符。
const isEven = num => num % 2 === 0;
isEven(1) // false
isEven(2) // true
  • 模数运算符有一些特殊情况:
    • 如果操作数中的一个是NaN ,则操作返回NaN
    • 如果被除数是Infinity ,或者如果除数是0 ,则操作返回NaN
    • 如果除数是Infinity ,或者被除数是0 ,则操作返回被除数。

(6)自增

自增 运算符用于将变量的值增加1。它可以应用于NumberBigInt 类型的操作数,根据它是后缀形式还是前缀形式,其行为会有所不同。

A、 后缀自增

如果运算符放在操作数后面(num++ ),则增量操作在返回值之后执行。在这种情况下,变量的原始值在当前表达式中使用,然后在之后递增变量的值:

let num = 5;
//num的原始值5在当前表达式中使用
const result = num++;
console.log(result); // 5
// 之后递增num的值
console.log(num); // 6

B、前缀自增

如果运算符放在操作数前面(++num ),则增量操作在返回值之前执行。在这种情况下,首先递增变量的值,然后在当前表达式中使用更新后的值:

let num = 5;
const result = ++num;
// 先递增num的值
console.log(num); // 6
//然后在当前表达式中使用更新后的值
console.log(result); // 6

(7)自减

减量运算符 用于将变量的值减少1。与增量运算符类似,它可以应用于NumberBigInt 类型的操作数,根据它是后缀形式还是前缀形式,其行为会有所不同。

A、 后缀自减

当运算符放在操作数后面(num-- )时,减量操作在返回值之后执行。在这种情况下,变量的原始值在当前表达式中使用,然后在之后递减变量的值:

let num = 5;
const result = num--;
// num的原始值5在当前表达式中使用
console.log(result); // 5
// 之后递减num的值
console.log(num); // 4

B、前缀自减

当运算符放在操作数前面(--num )时,减量操作在返回值之前执行。在这种情况下,首先递减变量的值,然后在当前表达式中使用更新后的值:

let num = 5;
const result = --num;
// 先递减num的值
console.log(num); // 4
// 然后在当前表达式中使用更新后的值
console.log(result); // 4

C、注意

自增、自减运算符只能用于可以更改的变量!

const num = 5;
console.log(++num); // Uncaught TypeError: Assignment to constant variable.
console.log(num++); // Uncaught TypeError: Assignment to constant variable.
console.log(--num); // Uncaught TypeError: Assignment to constant variable.
console.log(num--); // Uncaught TypeError: Assignment to constant variable.

(8)其他算术运算符

A、 一元否定运算符-

用于否定数值,将其符号更改为相反的。例如,-5 将是数字5 的否定。

B、 一元加运算符+

用于显式将值转换为数字,当处理数字的字符串表示时很有用。例如,+'10' 将字符串'10' 转换为数字10

const num = '10';
const res = +num; // 一元运算符将String转换为Number
console.log(res) // 10
console.log(typeof res) // number
console.log(typeof num) // string

C、 指数运算符**

用于将一个数值提升到某个幂次方。例如,2 ** 3 表示2的3次幂,结果是8。

3、赋值运算符

赋值运算符 用于将值赋给变量。它们还提供了一种简洁有效的方式,根据表达式或其他值来更新变量的值。除了基本的赋值运算符(= )之外,JavaScript 还提供了复合赋值运算符,它们将算术或逻辑操作与赋值结合在一起。

(1) 赋值:=

此运算符用于将一个值赋给一个变量。它允许我们将一个值存储在变量中,以便我们可以在代码中稍后使用和引用它:

const num = 4; // 将值 4 赋给变量 num
const squared = num * num; // 将值 16 赋给变量 squared

注意:赋值 运算符= 可以链接在一起,以在一行中将相同的值分配给多个变量

const a = b = c = 10; // 将值 10 分配给变量 a、b 和 c
console.log(a, b, c); // 输出 10 10 10

(2) 加法赋值:+=

加法赋值运算符 是一种复合运算符,它执行一步操作和赋值。具体来说,它将右操作数加到左操作数上,然后将结果分配给左操作数:

let num = 10;
num += 5;
console.log(num); // 15
  • 这个运算符不仅限于数字。它也可以用于字符串连接:
let greeting = 'Hello, ';
greeting += 'world';
console.log(greeting ) // Hello, World!
  • 当操作数不是相同类型时,JavaScript 会应用与类型强制转换相同的规则
let greeting = 'Hello, ';
greeting += 42 // 'Hello, 42'

(3) 减法赋值:-=

减法赋值运算符 是另一种复合运算符,它执行一步操作和赋值。它从左操作数中减去右操作数,然后将结果分配给左操作数:

let num = 10;
num -= 5 // 5
  • 与其他 JavaScript 运算符一样,当操作数不是相同类型时,-= 运算符会在进行赋值时进行类型强制转换;

如果可以将一个操作数转换为数字,JavaScript 就会这样做:

let num = '10';
num -= 5 // num 现在是 5(数字),而不是 '5'(字符串)
console.log(num) // 5
console.log(typeof num) // number

否则,结果是 NaN

let name = 'Jim';
name -= 5 
console.log(name)// NaN

(4) 乘法赋值:*=

乘法赋值运算符 将左操作数乘以右操作数,然后将结果分配回左操作数:

let num = 5;
num *= 3 // 15
  • 当我们使用不同类型的操作数时,JavaScript 会尝试将非数字字符串操作数转换为数字:
    let num = '5';
    num *= 3 // num 现在是 15(数字),而不是 '15'(字符串)
    console.log(num) // 15
    console.log(typeof num) // number
  • 如果字符串操作数无法转换为数字,则结果为 NaN
    let num = 'tom';
    num *= 3 
    console.log(num) // NaN
    console.log(typeof num) // number

(5) 除法赋值:/=

除法赋值运算符 在两个操作数上执行操作,然后将结果分配回左操作数:

let num = 10;
num /= 2 // 5

否则,我们在上面关于除法运算符的部分讨论过的规则也适用:

let num = 3;
num /= '-0.5' // -6

num = 3;
num /= 0 // Infinity

num = 3;
num /= 'Jim' // NaN

(6) 取模赋值:%=

取模赋值运算符 对两个操作数执行取模运算,然后将结果分配给左操作数:

let num = 10;
num %= 3 // 1

否则,我们在上面关于取模运算符的部分讨论过的规则也适用:

let num = 3;
num %= '3' // 0

num = 3;
num %= 0 // NaN

num = 3;
num %= 'Jim' // NaN

(7) 指数赋值:*=

指数赋值运算符执行指数运算,其中左操作数是底数,右操作数是指数,然后将结果分配给左操作数:

let num = 2;
num **= 3 // 8

与之前一样,当第二个操作数不是数字时,JavaScript 将尝试以不同程度的成功进行转换:

let num = 2;
num **= '3' // 8

num = 2;
num **= 'Jim' // NaN

4、 位运算赋值运算符

这些 JavaScript 赋值运算符中的每一个都执行与操作数的二进制表示的特定位运算,并将结果分配回左操作数。

  • 位与赋值(&=
  • 位或赋值(|=
  • 位异或赋值(^=
  • 左移位赋值(<<=
  • 右移位赋值(>>=
  • 无符号右移位赋值(>>>=

5、 比较运算符 ==、===

(1) 相等性:==

相等运算符 用于检查两个值是否相等。它返回一个布尔结果。要注意是,此比较运算符执行松散的相等性检查,这意味着如果操作数的类型不同,JavaScript 将尝试将它们转换为公共类型,然后再进行比较

1 == 1 // true,两个操作数都是数字
1 == '1' // true,字符串被转换为数字

当涉及到对象和数组时== 运算符检查它们是否引用内存中的相同位置,而不是它们的内容是否相同:

<script>
    const array1 = [1, 2, 3];
    const array2 = [1, 2, 3];
    console.log(array1 == array2); // false,尽管它们看起来一样

    const array3 = array1;
    console.log(array1 == array3); // true,它们引用相同的内存位置
</script>

说明:在这种情况下,JavaScript 不会尝试转换和比较对象或数组中的值。相反,它检查它们是否是相同的对象(即它们是否占用相同的内存空间)。

(2) 不等性:!=

不等运算符 用于检查两个值是否不相等。与 == 运算符类似,它执行松散的不等比较。这意味着,如果它们是不同类型,它会尝试将操作数转换为公共类型,然后再进行比较

1 != 2 // true,1 不等于 2
1 != '1' // false,字符串被转换为数字,1 等于 1
'apple' != 'orange' // true,字符串不同

== 运算符类似,当涉及对象和数组时,!= 运算符检查它们是否引用内存中的相同位置,而不是它们的内容是否相同。

(3) 严格相等性 (===) 和严格不等性 (!==)

  • 严格相等性严格不等性 比较运算符类似于它们的非严格对应物 (==!= ),但它们不执行类型强制转换如果操作数是不同类型的,无论它们的值是否相等,它们都被视为不同
1 === '1' // false,因为 Number 不严格等于 String
1 !== '1' // true,因为 Number 不严格等于 String
null === undefined // false,即使 null == undefined 为 true
true === 1 // false,因为 Boolean 不严格等于 Number
  • 对于对象和数组,严格相等运算符的行为与松散相等运算符相同:它检查它们是否引用相同的对象,而不是它们的内容是否相同。

  • NaN 是一个特殊情况。它是 JavaScript 中唯一不严格等于自身的值:

NaN === NaN // false

(4) 大于:>

大于运算符 检查左操作数是否大于右操作数,返回一个布尔结果。

这种比较对数值值来说很简单:

4 > 3 // true
2 > 2 // false

当比较非数值值时,JavaScript 应用一种转换过程,使它们可以进行比较。

  • 如果两个值都是字符串,它们将根据它们在 Unicode 字符集中的相应位置进行比较
'3' > '2' // true
'abc' > 'def' // false
  • 如果一个或两个操作数不是字符串,JavaScript 将尝试将它们转换为比较用的数字
'10' > 2 // true,将 '10' 转换为数字进行比较

在这种转换过程中,特定值的特殊规则适用。例如,null 被转换为 0undefined 被转换为 NaN ,而布尔值 truefalse 分别被转换为 10 。但是,如果在转换后任何一个操作数是 NaN ,则运算符始终返回 false

10 > 'Jim' // false,将 'Jim' 转换为数字得到 NaN

(5) 小于:<

小于运算符 如果左操作数小于右操作数,则返回 true,否则返回 false。与大于运算符一样,在进行比较之前使用强制类型转换将操作数转换为公共类型,只是操作数的顺序相反:

5 < 10 // true,5 小于 10
'10' <

 '2' // true,因为比较是按字典顺序进行的
'10' < 2 // false,字符串 '10' 被强制转换为数字

10 < 'Jim' // false,将 'Jim' 转换为数字得到 NaN

(6) 大于等于 (>=) 和小于等于 (<=)

大于等于 (>=) 和 小于等于 (<=) 运算符与它们的 <> 对应物类似,只是多了一个相等条件。

  • 对于 >= 运算符,如果左操作数大于或等于右操作数,则返回 true,否则返回 false

  • 对于 <= 运算符,如果左操作数小于或等于右操作数,则返回 true,否则返回 false

  • 强制类型转换和类型转换规则与上面介绍的 <> 运算符相同:

5 >= 5 // true,5 等于 5
5 >= 6 // false,5 不大于 6
'10' >= '2' // false,'1' 的 Unicode 为 49,而 '2' 的 Unicode 为 50
'10' <= 20 // true,字符串 '10' 被强制转换为数字
5 >= false // true,false 被强制转换为 0
5 <= true // false,true 被强制转换为 1
null >= -1 // true,null 被强制转换为 0
undefined <= 0 // false,undefined 被强制转换为 NaN

6、 逻辑运算符

JavaScript 中的 逻辑运算符 提供了一种同时处理多个条件的方式。它们是编程中决策构造的重要组成部分,例如 if 语句和 for 循环。

(1) 逻辑与:&&

返回布尔值: 当与布尔值一起使用时,逻辑与运算符返回布尔值,如果所有条件都为 true,否则返回 false

返回非布尔值: 然而,与非布尔值一起使用时,它变得非常有趣:

  • 该运算符从左到右评估条件。
  • 如果它遇到一个可以转换为 false(称为假值)的值,它会停止并返回该值。–遇到false停止并返回;
  • 如果所有值都为真值,则返回最后一个真值。–全真就返回最后一个;
true && true // true
true && false // false
'apple' && 'banana' // 'banana'--两个都不是布尔值,而两个都不是空串,所以返回最后一个真值串
'' && 'banana' // ''--空串为假值,直接就返回了

&& 运算符返回操作数的值,使其成为条件执行和设置默认值的多功能工具。例如,我们可以使用 && 运算符仅在满足某个条件时执行函数或一段代码:

const userIsLoggedIn = true;
userIsLoggedIn && renderWelcomeMessage();

在这种情况下,只有当 userIsLoggedIntrue 时,才会执行 renderWelcomeMessage。如果 userIsLoggedInfalse,操作将在 userIsLoggedIn 处停止,renderWelcomeMessage 将不会被调用。这种模式在 React 中经常用于有条件地渲染组件。

(2) 逻辑或:||

返回布尔值: 当与布尔值一起使用时,逻辑或运算符返回布尔值,至少一个条件为 true则返回true,否则返回 false

返回非布尔值: 它还可以返回非布尔值,执行所谓的短路求值。它从左到右评估条件,停在并返回第一个真值条件的值。如果所有条件都是假值,它将返回最后一个假值:–遇到true停止并返回,全假返回最后一个;

true || false // true
false || true // true
'Hello' || 'World' // 'Hello'
'' || 'World' // 'World'
0 || '' // ''

(3)逻辑非:!

逻辑非运算符用于反转条件或表达式的布尔值。与 &&|| 运算符不同,! 运算符始终返回布尔值

如果条件为真值(即可以转换为 true),则该运算符返回 false。如果条件为假值(即可以转换为 false),则该运算符返回 true

!true // false
!false // true
!'Hello' // false
!'' // true
!0 // true

我们可以使用 ! 运算符两次将一个值转换为其布尔等效值:

!!'Hello' // true
!!'' // false
!!0 // false

(4) 空值合并运算符:??

空值合并运算符 用于检查其左侧的值是否为 nullundefined,如果是,它将返回右侧的值。否则,它将返回左侧的值。

尽管在某些方面与 || 运算符相似,但 ?? 运算符在处理假值时有所不同。

|| 运算符在左侧操作数为任何假值(如 nullundefinedfalse0NaN'')时会返回右操作数,?? 运算符只在左操作数为 nullundefined 时才会返回右操作数:

null ?? '默认字符串' // '默认字符串'
undefined ?? '默认字符串' // '默认字符串'
'' ?? '默认字符串' // ''
0 ?? 100 // 0

(5) 使用逻辑运算符设置默认值

||?? 逻辑运算符在程序中设置默认值时非常有用。

下面是使用 || 运算符进行设置默认值的示例:

const userColorPreference = null;
const defaultColor = '蓝色';
const color = userColorPreference || defaultColor; // '蓝色'

这是使用 ?? 运算符的示例:

const userColorPreference = null;
const defaultColor = '蓝色';
const color = userColorPreference ?? defaultColor; // '蓝色'

这些逻辑运算符之间的主要区别(如上所示)在于它们如何处理假值:

const userColorPreference = '';
const defaultColor = '蓝色';
const color1 = userColorPreference || defaultColor; // '蓝色'
const color2 = userColorPreference ?? defaultColor; // ''

7、 位运算符

JavaScript 中的位运算符提供了一种在二进制级别执行操作的方式,直接操作数字的二进制表示。虽然这些运算符在特定任务(如数据编码、解码和处理)中可能很有用,但在日常 JavaScript 编程中并不经常使用。

(1) 位与运算符:&

位与运算符 对整数的二进制表示进行位与操作。它返回一个新数字,其中的位如果在两个操作数中的相同位置上都为 1,则设置为 1。否则,将其设置为 0:

// 5 的二进制表示:101
// 3 的二进制表示:011
5 & 3 // 1(对应二进制 001)

(2) 位或运算符:|

位或运算符 的工作方式类似于 & 运算符,但它设置为 1 的位,如果操作数中相同位置上的位至少有一个为 1:

// 5 的二进制表示:101
// 3 的二进制表示:011
5 | 3 // 7(对应二进制 111)

(3) 位异或运算符:^

位异或运算符 有点不同。它仅在操作数中的相同位置上的位不同(一个为 1,另一个为 0)时设置位为 1:

// 5 的二进制表示:101
// 3 的二进制表示:011
5 ^ 3 // 6(对应二进制 110)

(4) 位非运算符:~

位非运算符 (~) 反转其操作数的位。它将二进制表示中的 1 变为 0,0 变为 1:、

// 5 的二进制表示:101
~5 // -6(对应二进制的补码,即 010)

注意二进制补码 是一种表示负整数的二进制符号表示方法。

8、 位移运算符:<<, >>, >>>

位移运算符 用于将二进制数的位向左或向右移动。在 JavaScript 中,有三种类型:左位移 (<<)、右位移 (>>) 和零填充右位移 (>>>)。

左位移位运算符 (<<) 将位向左移动,并在右侧填充零。右位移运算符 (>>) 将位向右移动,舍弃移出的位。零填充右位移运算符 (>>>) 也将位向右移动,但在左侧填充零。

这些运算符在日常 JavaScript 编程中较少使用,但在更专业的领域,如低级编程、二进制数据处理和某些类型的数学计算中有用。

9、 条件(三元)运算符:? :

条件三元运算符 (? :) 是在 JavaScript 代码中做决策的一种简洁方式。它因为是唯一接受三个操作数的运算符而得名。这个条件运算符的语法如下:

条件 ? 如果为真执行的表达式 : 如果为假执行的表达式

该运算符首先评估条件。如果条件为 true,则执行 如果为真执行的表达式,如果条件为 false,则执行 如果为假执行的表达式

const age = 15;
const status = age >= 18 ? '成年人' : '未成年人'; // '未成年人'

在上面的代码中,三元运算符检查 age 是否大于或等于 18。由于 age 是 15,条件求值为 false,因此将 '未成年人' 分配给 status 变量。

这个运算符可以是一种方便的方式来编写简洁的 if-else 语句,但如果过度使用或在复杂条件中使用,可能会使代码难以阅读。

10、 扩展运算符:...

扩展运算符 (...) 允许在期望零个或多个参数或元素的位置上展开可迭代对象(如数组或字符串)。它可以用于函数调用、数组字面量和对象字面量中:

// 在函数调用中
const numbers = [1, 2, 3];
console.log(...numbers); // 1 2 3

// 在数组字面量中
const moreNumbers = [4, 5, ...numbers];
console.log(moreNumbers); // [4, 5, 1, 2, 3]

// 在对象字面量中
const obj1 = { a: 1, b: 2 };
const obj2 = { ...obj1, c: 3 };
console.log(obj2); // { a: 1, b: 2, c: 3 }

扩展运算符可以用于创建数组或对象的副本、连接数组或将数组的元素作为参数传递给函数。

11、 逗号运算符:,

逗号运算符 (,) 允许在序列中评估多个表达式,并返回最后一个表达式的结果。这些表达式从左到右进行评估。

当我们需要在只允许一个表达式的位置包含多个表达式时,逗号运算符特别有用,例如在 for 循环的初始化或更新部分:

for(let i = 0, j = 10; i <= 10; i++, j--) {
  console.log(`i: ${i}, j: ${j}`);
}

上面的代码中,逗号运算符用于在 for 循环中声明和更新两个变量 (ij )。

12、 可选链运算符:?.

可选链 是 JavaScript 的一个相对较新的特性(截止到 ES2020),它简化了访问对象深层嵌套属性的过程。它通过提供一种方式来尝试检索属性值,而无需明确检查链中的每个引用是否存在,从而帮助我们编写更干净、更安全的代码:

const user = {
  name: 'Jim',
  address: {
    street: '123 Hochstraße',
    city: 'Munich'
  }
};

user?.address?.city // 'Munich'
user?.contacts?.email // undefined

在上面的示例中,user?.address?.city 尝试访问 user.addresscity 属性,如果 useruser.address 都存在,则返回 city 的值。否则,它将返回 undefined。这种方法避免了 JavaScript 中的一个常见陷阱,即尝试访问 undefinednull 的属性会导致 TypeError

const user = {
  name: 'Jim',
  address: {
    street: '123 Hochstraße',
    city: 'Munich'
  }
};

user.contacts.email // Uncaught TypeError: Cannot read properties of undefined (reading 'email')

在可选链之前,JavaScript 开发人员不得不使用冗长的条件逻辑来避免此类错误:

let email;
if (user && user.contacts) {
  email = user.contacts.email;
} else {
  email = '未指定';
}

email // '未指定'

13、 管道运算符:|>

管道运算符 (|>) 旨在提高代码的可读性,该代码否则将使用嵌套函数调用编写。它允许我们获取一个表达式的结果并将其传递给下一个表达式。这在我们对值应用一系列转换时特别有用:

const result = exclaim(capitalize(doubleSay('hello')));
console.log(result);  //=> 'HELLO, HELLO!'

使用管道运算符,我们可以像这样重写这段代码:

const result = 'hello'
  |> doubleSay // 将hello传给doubleSay得到结果
  |> capitalize // 将doubleSay得到的结果传给capitalize 
  |> exclaim; // 将capitalize 的结果传给exclaim,最后赋值给result

console.log(result);  //=> 'HELLO, HELLO!'

14、 分组运算符:()

JavaScript 中的分组运算符 (()) 用于更改表达式中评估的优先级顺序。这个运算符不对其值执行任何操作,但它控制了表达式中计算的顺序。

例如,乘法和除法的优先级高于加法和减法。这意味着,在表达式 2 + 3 * 4 中,首先执行乘法,得到 2 + 12,然后执行加法,得到 14

如果我们想改变操作顺序,可以使用分组运算符。例如,在前面的示例中,如果我们希望加法在乘法之前执行,可以编写 (2 + 3) * 4。在这种情况下,首先执行加法,得到 5 * 4

,然后执行乘法,得到 20

分组运算符允许我们确保按照我们打算的顺序执行操作,这在更复杂的数学或逻辑表达式中非常重要。