+
)==
与 ===
==
和 !=
)===
和 !==
)===
更严格:Object.is()
JavaScript 的运算符可能看起来很奇怪。通过以下两条规则,它们更容易理解
如果运算符获取的操作数类型不正确,它很少会抛出异常。相反,它会_强制_(自动转换)操作数,以便它可以使用它们。让我们看两个例子。
首先,乘法运算符只能处理数字。因此,它在计算结果之前将字符串转换为数字。
> '7' * '3'21
其次,用于访问对象属性的方括号运算符 ([ ]
) 只能处理字符串和符号。所有其他值都将强制转换为字符串
const obj = {};
'true'] = 123;
obj[
// Coerce true to the string 'true'
.equal(obj[true], 123); assert
如前所述,大多数运算符仅适用于原始值。如果操作数是对象,它通常会被强制转换为原始值——例如
> [1,2,3] + [4,5,6]'1,2,34,5,6'
为什么?加法运算符首先将其操作数强制转换为原始值
> String([1,2,3])'1,2,3'
> String([4,5,6])'4,5,6'
接下来,它连接两个字符串
> '1,2,3' + '4,5,6''1,2,34,5,6'
+
)加法运算符在 JavaScript 中的工作方式如下
字符串模式允许我们使用 +
来组合字符串
> 'There are ' + 3 + ' items''There are 3 items'
数字模式意味着如果两个操作数都不是字符串(或成为字符串的对象),则所有内容都将强制转换为数字
> 4 + true5
Number(true)
为 1
。
普通赋值运算符用于更改存储位置
= value; // assign to a previously declared variable
x .propKey = value; // assign to a property
obj= value; // assign to an Array element arr[index]
变量声明中的初始化程序也可以看作一种赋值形式
const x = value;
let y = value;
JavaScript 支持以下赋值运算符
+= -= *= /= %=
[ES1]+=
也可用于字符串连接**=
[ES2016]&= ^= |=
[ES1]<<= >>= >>>=
[ES1]||= &&= ??=
[ES2021]逻辑赋值运算符与其他复合赋值运算符的工作方式不同
赋值运算符 | 等价于 | 仅在 a 为 时赋值 |
---|---|---|
a ||= b |
a || (a = b) |
假值 |
a &&= b |
a && (a = b) |
真值 |
a ??= b |
a ?? (a = b) |
空值 |
为什么 a ||= b
等价于以下表达式?
a || (a = b)
为什么不等价于这个表达式?
a = a || b
前一个表达式具有 短路 的优点:仅当 a
求值为 false
时才会计算赋值。因此,仅在必要时才执行赋值。相反,后一个表达式始终执行赋值。
有关 ??=
的更多信息,请参阅 §14.4.5 “空值合并赋值运算符 (??=
) [ES2021]”。
对于 || && ??
以外的运算符 op
,以下两种赋值方式是等效的
myvar op= value
myvar = myvar op value
例如,如果 op
是 +
,那么我们将得到运算符 +=
,其工作方式如下。
let str = '';
+= '<b>';
str += 'Hello!';
str += '</b>';
str
.equal(str, '<b>Hello!</b>'); assert
==
与 ===
JavaScript 有两种相等运算符:宽松相等 (==
) 和严格相等 (===
)。建议始终使用后者。
==
和 ===
的其他名称
==
也称为_双等号_。它在语言规范中的官方名称是 _抽象相等比较_。===
也称为_三等号_。==
和 !=
)宽松相等是 JavaScript 的怪癖之一。它经常强制转换操作数。其中一些强制转换是有意义的
> '123' == 123true
> false == 0true
其他的则不那么有意义
> '' == 0true
如果(且仅当!)另一个操作数是原始值时,对象才会被强制转换为原始值
> [1, 2, 3] == '1,2,3'true
> ['1', '2', '3'] == '1,2,3'true
如果两个操作数都是对象,则仅当它们是同一个对象时才相等
> [1, 2, 3] == ['1', '2', '3']false
> [1, 2, 3] == [1, 2, 3]false
> const arr = [1, 2, 3];
> arr == arrtrue
最后,==
认为 undefined
和 null
相等
> undefined == nulltrue
===
和 !==
)严格相等从不强制转换。只有当两个值的类型相同时,它们才相等。让我们回顾一下之前与 ==
运算符的交互,看看 ===
运算符会做什么
> false === 0false
> '123' === 123false
只有当另一个值是同一个对象时,对象才等于该值
> [1, 2, 3] === '1,2,3'false
> ['1', '2', '3'] === '1,2,3'false
> [1, 2, 3] === ['1', '2', '3']false
> [1, 2, 3] === [1, 2, 3]false
> const arr = [1, 2, 3];
> arr === arrtrue
===
运算符不认为 undefined
和 null
相等
> undefined === nullfalse
我建议始终使用 ===
。它使您的代码更易于理解,并避免您不得不考虑 ==
的怪癖。
让我们看看 ==
的两个用例,以及我建议改为做什么。
==
的用例:与数字或字符串进行比较==
允许您检查值 x
是否为数字或该数字的字符串形式——只需一次比较
if (x == 123) {
// x is either 123 or '123'
}
我更喜欢以下两种替代方案中的任何一种
if (x === 123 || x === '123') ···
if (Number(x) === 123) ···
您也可以在第一次遇到 x
时将其转换为数字。
==
的用例:与 undefined
或 null
进行比较==
的另一个用例是检查值 x
是否为 undefined
或 null
if (x == null) {
// x is either null or undefined
}
这段代码的问题在于,您无法确定某人是有意这样写的,还是他们打错了字,本意是 === null
。
我更喜欢以下两种替代方案中的任何一种
if (x === undefined || x === null) ···
if (!x) ···
第二种替代方案的缺点是它接受 undefined
和 null
以外的值,但这是 JavaScript 中一种既定的模式(将在 §15.3 “基于真值的 존재 확인” 中详细解释)。
以下三个条件也大致等效
if (x != null) ···
if (x !== undefined && x !== null) ···
if (x) ···
===
更严格:Object.is()
方法 Object.is()
比较两个值
> Object.is(123, 123)true
> Object.is(123, '123')false
它甚至比 ===
更严格。例如,它认为 NaN
(涉及数字的计算的错误值)等于自身
> Object.is(NaN, NaN)true
> NaN === NaNfalse
这偶尔会有用。例如,您可以使用它来实现 Array 方法 .indexOf()
的改进版本
const myIndexOf = (arr, elem) => {
return arr.findIndex(x => Object.is(x, elem));
; }
myIndexOf()
在数组中查找 NaN
,而 .indexOf()
则不会
> myIndexOf([0,NaN,2], NaN)1
> [0,NaN,2].indexOf(NaN)-1
结果 -1
表示 .indexOf()
在数组中找不到其参数。
运算符 | 名称 |
---|---|
< |
小于 |
<= |
小于或等于 |
> |
大于 |
>= |
大于或等于 |
JavaScript 的排序运算符(表 3)适用于数字和字符串
> 5 >= 2true
> 'bar' < 'foo'true
<=
和 >=
基于严格相等。
排序运算符不适用于人类语言
排序运算符不适用于比较人类语言中的文本,例如,涉及大写或重音符号时。详细信息在 §20.6 “比较字符串” 中解释。
以下运算符在本的其他部分介绍
??
)接下来的两小节 将讨论两个很少使用的运算符。
逗号运算符有两个操作数,它会计算两个操作数并返回第二个操作数
> 'a', 'b''b'
有关此运算符的更多信息,请参阅 _Speaking JavaScript_。
void
运算符void
运算符计算其操作数并返回 undefined
> void (3 + 2)undefined
有关此运算符的更多信息,请参阅 _Speaking JavaScript_。
测验
请参阅 测验应用程序。