三、 运算符
3.1 算术运算符
3.1.1 加法运算符
加法运算符(+)是最常见的运算符,用来求两个数值的和。如果有字符串就变成字符串的拼接。
加法运算符是在运行时决定是执行相加还是连接,运算子的不同,导致了不同的语法行为,这种现象称为“重载”。
1.对象的相加
如果运算子是对象,必须先转为原始类型的值,然后再相加。
var obj = { p: 1 };
obj + 2 // "[object Object]2"
对象转为原始类型值规则如下:
- 自动调用对象的valueOf()方法,一般来说,对象的valueOf方法总是返回对象自身
- 然后再调用对象的toString()方法,对象的toString方法默认返**[object Object]**
- 这里有一个特例,如果运算子是一个Date对象的实例,那么会优先执行toString方法。
let date = new Date();
date.toString() // Mon Jul 12 2021 21:49:13 GMT+0800 (中国标准时间)
3.1.2 自增和自减运算符
它们是一元运算符,只需要一个运算子。自增和自减运算符有一个需要注意的地方,就是放在变量之后,会先返回变量操作前的值,再进行自增/自减操作,放在变量之前,会先进行自增/自减操作,再返回变量操作后的值。
var x = 1;
var y = 1;
x++ // 1
++y // 2
3.1.3 数值运算符(+)
数值运算符的作用在于将任何值转为数值,与Number函数的作用相同。
+true // 1
+[] // 0
+{} // NaN
3.2 比较运算符
比较运算符分为两类,相等比较和非相等比较。对于非相等比较,算法是先看两者是否都是字符串,如果是则照字典顺序比较,否则,将它们都转为数值,再进行比较。
1. 都是字符串的比较
'cat' > 'dog' // false
'cat' > 'catalog' // false
2. 非字符串的比较
2.1 原始类型值
如果两个运算子都是原始类型的值,则是先转成数值再比较。
5 > '4' // true
// 等同于 5 > Number('4')
true > false // true
// 等同于 Number(true) > Number(false)
// 即 1 > 0
这里需要注意与NaN的比较。任何值(包括NaN本身)与NaN使用非相等运算符进行比较,返回的都是false。
2.2 对象
如果运算子是对象,会转为原始类型的值,再进行比较。空数组返回一个空字符串。
[2] > [1] // true
[2] > [11] // true
{ x: 2 } >= { x: 1 } // true
3.3 布尔运算符
3.3.1 取反运算符(!)
取反运算符是一个感叹号,用于将布尔值变为相反值,对于非布尔值,取反运算符会将其转为布尔值。只有6个值为false(null undefined false 0 NaN ")
3.3.2 且运算符(&&)
且运算符(&&)往往用于多个表达式的求值。
它的运算规则是:如果第一个运算子的布尔值为true,则返回第二个运算子的值(注意是值,不是布尔值);如果第一个运算子的布尔值为false,则直接返回第一个运算子的值,且不再对第二个运算子求值。
't' && '' // ""
't' && 'f' // "f"
't' && (1 + 2) // 3
'' && 'f' // ""
'' && '' // ""
3.4 二进制位运算符
3.4.1 概述
二进制位运算符用于直接对二进制位进行计算,一共有7个。所有的位运算都只对整数有效。二进制否运算遇到小数时,也会将小数部分舍去,只保留整数部分。
- 二进制或运算符(or):符号为 | ,表示若两个二进制位都为0,则结果为0,否则为1。
- 二进制与运算符(and):符号为 & ,表示若两个二进制位都为1,则结果为1,否则为0。
- 二进制否运算符(not):符号为 ~ ,表示对一个二进制位取反。
- 异或运算符(xor):符号为 ^ ,表示若两个二进制位不相同,则结果为1,否则为0。、
- 左移运算符(left shift):符号为 << ,详见下文解释。
- 右移运算符(right shift):符号为 >> ,详见下文解释。
- 头部补零的右移运算符(zero filled right shift):符号为>>>,详见下文解释。
这些运算符直接处理每一个比特位,是非常底层的运算,好处是速度快,缺点是不够直观。在 JavaScript 内部,做位运算的时候,是以32位带符号的整数进行运算的,并且返回值也是一个32位带符号的整数。
3.4.2 二进制或运算符
0 | 3 // 3
相当于 00 | 11 =》 二进制11,也就是3
位运算只对整数有效,遇到小数时,会将小数部分舍去,只保留整数部分。 所以,将一个小数与0进行二进制或运算,等同于对该数去除小数部分,即取整数位。
2.9 | 0 // 2
-2.9 | 0 // -2
3.4.3 二进制否运算符
二进制否运算符(~)将每个二进制位都变为相反值(0变为1,1变为0)
~ 3 // -4
取反运算比较复杂,简单记忆就是 一个数与自身的取反值相加等于 -1。
3.4.5 异或运算符
异或运算(^)在两个二进制位不同时返回1,相同时返回0。
“异或运算”有一个特殊运用,连续对两个数a和b进行三次异或运算,a^=b; b^=a; a^=b;,可以互换它们的值。这意味着,使用“异或运算”可以在不引入临时变量的前提下,互换两个变量的值。
var a = 10;
var b = 99;
a ^= b, b ^= a, a ^= b;
a // 99
b // 10
3.4.6 左移运算符
左移运算符(<<)表示将一个数的二进制值向左移动制定的位数,尾部补零,即乘以2的指定次方,
// 4 的二进制形式为100,
// 左移一位为1000(即十进制的8)
// 相当于乘以2的1次方
4 << 1
// 8
-4 << 1
// -8
3.4.7 右移运算符
右移运算符(>>)表示将一个数的二进制值向右移动指定的位数,右移运算符基本上相当于除以2的指定次方(最高位即符号位参与移动)。右移运算可以模拟 2 的整除运算。
4 >> 1 // 2
-4 >> 1 // -2
5 >> 1
// 2
// 相当于 5 / 2 = 2
21 >> 2
// 5
// 相当于 21 / 4 = 5
21 >> 3
// 2
// 相当于 21 / 8 = 2
21 >> 4
// 1
// 相当于 21 / 16 = 1
3.4.8 头部补零右移运算符
头部补零的右移运算符(>>>)与右移运算符(>>)只有一个差别,就是一个数的二进制形式向右移动时,头部一律补零,而不考虑符号位。
所以,该运算总是得到正值。对于正数,该运算的结果与右移运算符(>>)完全一致,区别主要在于负数。
3.5 其他运算符,运算顺序
3.5.1 void 运算符
void运算符的作用是执行一个表达式,然后不返回任何值,或者说返回undefined。
void 0 // undefined
void(0) // undefined
这个运算符的主要用途是浏览器的书签工具(Bookmarklet),以及在超级链接中插入代码防止网页跳转。
<a href="javascript: void(document.form.submit())">
提交
</a>
用户点击链接提交表单,但是不产生页面跳转。