+)== 与 ===== 和 !=)=== 和 !==)=== 更严格:Object.is()JavaScript 的运算符可能看起来很奇怪。通过以下两条规则,它们更容易理解
如果运算符获取的操作数类型不正确,它很少会抛出异常。相反,它会_强制_(自动转换)操作数,以便它可以使用它们。让我们看两个例子。
首先,乘法运算符只能处理数字。因此,它在计算结果之前将字符串转换为数字。
> '7' * '3'
21其次,用于访问对象属性的方括号运算符 ([ ]) 只能处理字符串和符号。所有其他值都将强制转换为字符串
const obj = {};
obj['true'] = 123;
// Coerce true to the string 'true'
assert.equal(obj[true], 123);如前所述,大多数运算符仅适用于原始值。如果操作数是对象,它通常会被强制转换为原始值——例如
> [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 + true
5Number(true) 为 1。
普通赋值运算符用于更改存储位置
x = value; // assign to a previously declared variable
obj.propKey = value; // assign to a property
arr[index] = value; // assign to an Array element变量声明中的初始化程序也可以看作一种赋值形式
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 = '';
str += '<b>';
str += 'Hello!';
str += '</b>';
assert.equal(str, '<b>Hello!</b>');== 与 ===JavaScript 有两种相等运算符:宽松相等 (==) 和严格相等 (===)。建议始终使用后者。
== 和 === 的其他名称
== 也称为_双等号_。它在语言规范中的官方名称是 _抽象相等比较_。=== 也称为_三等号_。== 和 !=)宽松相等是 JavaScript 的怪癖之一。它经常强制转换操作数。其中一些强制转换是有意义的
> '123' == 123
true
> false == 0
true其他的则不那么有意义
> '' == 0
true如果(且仅当!)另一个操作数是原始值时,对象才会被强制转换为原始值
> [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 == arr
true最后,== 认为 undefined 和 null 相等
> undefined == null
true=== 和 !==)严格相等从不强制转换。只有当两个值的类型相同时,它们才相等。让我们回顾一下之前与 == 运算符的交互,看看 === 运算符会做什么
> false === 0
false
> '123' === 123
false只有当另一个值是同一个对象时,对象才等于该值
> [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 === arr
true=== 运算符不认为 undefined 和 null 相等
> undefined === null
false我建议始终使用 ===。它使您的代码更易于理解,并避免您不得不考虑 == 的怪癖。
让我们看看 == 的两个用例,以及我建议改为做什么。
== 的用例:与数字或字符串进行比较== 允许您检查值 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 === NaN
false这偶尔会有用。例如,您可以使用它来实现 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 >= 2
true
> 'bar' < 'foo'
true<= 和 >= 基于严格相等。
排序运算符不适用于人类语言
排序运算符不适用于比较人类语言中的文本,例如,涉及大写或重音符号时。详细信息在 §20.6 “比较字符串” 中解释。
以下运算符在本的其他部分介绍
??)接下来的两小节 将讨论两个很少使用的运算符。
逗号运算符有两个操作数,它会计算两个操作数并返回第二个操作数
> 'a', 'b'
'b'有关此运算符的更多信息,请参阅 _Speaking JavaScript_。
void 运算符void 运算符计算其操作数并返回 undefined
> void (3 + 2)
undefined有关此运算符的更多信息,请参阅 _Speaking JavaScript_。
测验
请参阅 测验应用程序。