1、术语介绍
-
操作数: 是运算符操作的项目。如果我们将运算符视为一种操作,那么操作数就是该操作应用于的对象。例如,在表达式5 + 3中,
+
是运算符(加法操作),而5和3是操作数,即要相加的数字。在JavaScript中,操作数可以是不同类型的,如数字、字符串、变量,甚至更复杂的表达式。 -
强制类型转换: 是将一个值从一种原始类型转换为另一种原始类型的过程。例如,JavaScript可能会将数字更改为字符串,或者将非布尔值更改为布尔值。
- JavaScript中的原始类型包括
String
、Number
、BigInt
、Boolean
、undefined
、Symbol
或null
。 -
NaN
:代表不是数字。它是Number
类型的特殊值,表示无效或无法表示的数值。
- JavaScript中的原始类型包括
-
真值:是在布尔上下文中评估为
true
的值,而假值在布尔上下文中评估为false
。- 假值包括
false
、0
、''
、null
、undefined
、NaN
和BigInt(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连接起来。
- 在这种情况下,JavaScript试图将对象
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
,表示“不是数字”:
- 例如,如果我们尝试减去无法转换为数字的内容,JavaScript将返回
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。它可以应用于Number
或BigInt
类型的操作数,根据它是后缀形式还是前缀形式,其行为会有所不同。
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。与增量运算符类似,它可以应用于Number
或BigInt
类型的操作数,根据它是后缀形式还是前缀形式,其行为会有所不同。
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
被转换为 0
,undefined
被转换为 NaN
,而布尔值 true
和 false
分别被转换为 1
和 0
。但是,如果在转换后任何一个操作数是 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();
在这种情况下,只有当 userIsLoggedIn
为 true
时,才会执行 renderWelcomeMessage
。如果 userIsLoggedIn
为 false
,操作将在 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) 空值合并运算符:??
空值合并运算符 用于检查其左侧的值是否为 null
或 undefined
,如果是,它将返回右侧的值。否则,它将返回左侧的值。
尽管在某些方面与 ||
运算符相似,但 ??
运算符在处理假值时有所不同。
而 ||
运算符在左侧操作数为任何假值(如 null
、undefined
、false
、0
、NaN
、''
)时会返回右操作数,??
运算符只在左操作数为 null
或 undefined
时才会返回右操作数:
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 循环中声明和更新两个变量 (i
和 j
)。
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.address
的 city
属性,如果 user
和 user.address
都存在,则返回 city
的值。否则,它将返回 undefined
。这种方法避免了 JavaScript 中的一个常见陷阱,即尝试访问 undefined
或 null
的属性会导致 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
。
分组运算符允许我们确保按照我们打算的顺序执行操作,这在更复杂的数学或逻辑表达式中非常重要。