ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
## 12.运算符 > 原文: [http://exploringjs.com/impatient-js/ch_operators.html](http://exploringjs.com/impatient-js/ch_operators.html) > > 贡献者:[飞龙](https://github.com/wizardforcel) ### 12.1 理解运算符 JavaScript 的运算符可能看起来很古怪。使用以下两个规则,它们更容易理解: * 运算符将其操作数强制转换为适当的类型 * 大多数运算符只处理原始值 #### 12.1.1 运算符将其操作数强制转换为适当的类型 如果运算符获取的操作数不具有正确的类型,则很少会抛出异常。相反,它*强制转换*(自动转换)操作数,以便它可以使用它们。我们来看两个例子。 首先,乘法运算符只能用于数字。因此,它在计算结果之前将字符串转换为数字。 ```js > '7' * '3' 21 ``` 其次,用于访问对象属性的方括号运算符(`[ ]`)只能处理字符串和符号。所有其他值都强制转换为字符串: ```js const obj = {}; obj['true'] = 123; // Coerce true to the string 'true' assert.equal(obj[true], 123); ``` #### 12.1.2 大多数运算符只处理原始值 如前所述,大多数运算符仅处理原始值。如果操作数是对象,则通常将其强制转换为原始值。例如: ```js > [1,2,3] + [4,5,6] '1,2,34,5,6' ``` 为什么?加法运算符首先将其操作数强制转换为原始值: ```js > String([1,2,3]) '1,2,3' > String([4,5,6]) '4,5,6' ``` 接下来,它连接两个字符串: ```js > '1,2,3' + '4,5,6' '1,2,34,5,6' ``` ### 12.2 加法运算符(`+`) 加法运算符在 JavaScript 中如下工作: * 首先,它将两个操作数转换为原始值。然后它切换到以下两种模式之一: * 字符串模式:如果两个原始值中的一个是字符串,则它将另一个转换为字符串,连接两个字符串并返回结果。 * 数字模式:否则,它将两个操作数转换为数字,将它们相加并返回结果。 字符串模式让我们使用`+`来组合字符串: ```js > 'There are ' + 3 + ' items' 'There are 3 items' ``` 数字模式意味着如果操作数都不是字符串(或字符串对象),那么所有内容都被强制转换为数字: ```js > 4 + true 5 ``` `Number(true)`是`1`。 ### 12.3 赋值运算符 #### 12.3.1 普通赋值运算符 普通赋值运算符用于更改存储位置: ```js x = value; // assign to a previously declared variable obj.propKey = value; // assign to a property arr[index] = value; // assign to an Array element ``` 变量声明中的初始值设定也可以视为赋值形式: ```js const x = value; let y = value; ``` #### 12.3.2 复合赋值运算符 给定运算符`op`,以下两种赋值方式是等效的: ```js myvar op= value myvar = myvar op value ``` 例如,如果`op`是`+`,那么我们得到如下工作的运算符`+=`。 ```js let str = ''; str += '<b>'; str += 'Hello!'; str += '</b>'; ``` #### 12.3.3 所有复合赋值运算符的列表 * 算术运算符: ```js += -= *= /= %= **= ``` `+=`也适用于字符串连接 * 按位运算符: ```js <<= >>= >>>= &= ^= |= ``` ### 12.4 相等:`==`与`===` JavaScript 有两种相等运算符:松散相等(`==`)和严格相等(`===`)。建议总是使用后者。 #### 12.4.1 松散相等(`==`和`!=`) 松散相等是 JavaScript 的怪癖之一。它经常强制转换。其中一些强制转换是有道理的: ```js > '123' == 123 true > false == 0 true ``` 其他不是如此: ```js > '' == 0 true ``` 当且仅当另一个操作数是原始的,对象被强制转换为原始值: ```js > [1, 2, 3] == '1,2,3' true > ['1', '2', '3'] == '1,2,3' true ``` 如果两个操作数都是对象,则它们只有是相同的对象时才相等: ```js > [1, 2, 3] == ['1', '2', '3'] false > [1, 2, 3] == [1, 2, 3] false > const arr = [1, 2, 3]; > arr == arr true ``` 最后,`==`认为`undefined`和`null`相等: ```js > undefined == null true ``` ![](https://img.kancloud.cn/7b/17/7b17729df07100ffa1c582a9b46ac13a.svg) **`==`** 的其他名称 * [*抽象相等比较*](https://tc39.github.io/ecma262/#sec-abstract-equality-comparison)是语言规范中`==`的正式名称。 * *双等*是它的另一个名字。 #### 12.4.2 严格相等(`===`和`!==`) 严格相等永远不会强制转换。仅当两个值具有相同的类型,它们才相等。让我们重新审视我们之前与`==`运算符的交互,看看`===`运算符的作用: ```js > false === 0 false > '123' === 123 false ``` 当且仅当两个值是同一个对象,则一个对象才等于另一个值: ```js > [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`相等: ```js > undefined === null false ``` ![](https://img.kancloud.cn/7b/17/7b17729df07100ffa1c582a9b46ac13a.svg) **`===`** 的另一个名称 *三等*是`===`的另一个名称。 #### 12.4.3 建议:始终使用严格相等 我建议总是使用`===`。它使您的代码更容易理解,并使您不必考虑`==`的怪癖。 让我们看看`==`的两个用例以及我建议做的事情。 ##### 12.4.3.1 `==`的用例:比较数字或字符串 `==`允许您检查值`x`是数字还是作为字符串的数字 - 只需一次比较: ```js if (x == 123) { // x is either 123 or '123' } ``` 我更喜欢以下两种选择之一: ```js if (x === 123 || x === '123') ··· if (Number(x) === 123) ··· ``` 您第一次遇到它时也可以将`x`转换为数字。 ##### 12.4.3.2 `==`的用例:与`undefined`或`null`比较 `==`的另一个用例是检查值`x`是`undefined`还是`null`: ```js if (x == null) { // x is either null or undefined } ``` 这段代码的问题在于,你无法确定是否有人打算以这种方式编写,或者是否他们输错了并且意思是`=== null`。 我更喜欢以下两种选择之一: ```js if (x === undefined || x === null) ··· if (x) ··· ``` 第二种选择比使用`==`更加草率,但它在 JavaScript 中是一种成熟的模式(将在[布尔值](ch_booleans.html#falsiness-truthiness)的章节中详细解释,我们在其中看到真实性和虚假性)。 #### 12.4.4 甚至比`===`更严格:`Object.is()` 方法`Object.is()`比较两个值: ```js > Object.is(123, 123) true > Object.is(123, '123') false ``` 它甚至比`===`更严格。例如,它认为`NaN`,[数值计算](ch_numbers.html#nan)的错误值等于它自己: ```js > Object.is(NaN, NaN) true > NaN === NaN false ``` 这偶尔会有用。例如,您可以使用它来实现 Array 方法`.indexOf()`的改进版本: ```js const myIndexOf = (arr, elem) => { return arr.findIndex(x => Object.is(x, elem)); }; ``` `myIndexOf()`在数组中找到`NaN`,而`.indexOf()`不会: ```js > myIndexOf([0,NaN,2], NaN) 1 > [0,NaN,2].indexOf(NaN) -1 ``` 结果`-1`表示`.indexOf()`无法在 Array 中找到其参数。 ### 12.5 顺序运算符 表 3:JavaScript 的顺序运算符 | 运算符 | 名称 | | --- | --- | | `<` | 小于 | | `<=` | 小于等于 | | `>` | 大于 | | `>=` | 大于等于 | JavaScript 的顺序运算符(表 3)适用于数字和字符串: ```js > 5 >= 2 true > 'bar' < 'foo' true ``` `<=`和`>=`基于严格相等。 ![](https://img.kancloud.cn/20/ae/20ae605d8efee727618ed3803e87a6e5.svg) **顺序运算符不适合人类语言** 顺序操作符不能很好地用于比较人类语言中的文本,例如,当涉及大写或口音时。有关详细信息,请参阅[字符串](ch_strings.html#comparing-strings)的章节。 ### 12.6 各种其他运算符 * [逗号运算符](http://speakingjs.com/es5/ch09.html#comma_operator):`a, b` * [`void`运算符](http://speakingjs.com/es5/ch09.html#void_operator):`void 0` * 布尔运算符,字符串,数字,对象的运算符:在本书的其他地方介绍。 ![](https://img.kancloud.cn/ff/a8/ffa8e16628cad59b09c786b836722faa.svg) **测验** 参见[测验应用程序](ch_quizzes-exercises.html#quizzes)。