操作符(上)
什么是操作符
即操作数据值的一组符号,ECMAScript操作符能够对不同类型的值适用,包括String、Number、Boolean、甚至Object,加上js本身是弱语言,导致操作符的使用非常灵活。
一元操作符
1.递增和递减操作符(++和--)
递增和递减有两个版本:前置型和后置型
// 前置型
var age = 20
newAge = ++age + 2 //
console.log(newAge, age) // 23 21
// 后置型
var num = 20
newNum = num++ + 2
console.log(newNum, num) // 22 21
从以上代码可以看出,前置型操作符是在语句执行前改变变量(计算机领域被称为副效应),而后置型是在语句执行后改变变量。当然,在语句之后,它们的值是一样的,对之后的语句没有影响(递减符效果一样,只是从加变成减)。
这四个操作符对于String、Number、Boolean、甚至Object,在递增和递减前会把这些类型按照一定的规则转化为数值,然后执行操作。转化规则和Number函数转化规则一致。
递增和递减操作符无法直接对值进行操作,必须先保存到变量中。
2. 一元加减操作符
一元加减操作符就是数学上的加减非常简单,但是它对于非数值也可以进行操作,这个时候会像Number函数转化一样将非数值转化为数值再进行加减。
除此之外,它还可以进行数据转化,转化规则和Number函数转化规则一致。
s = '123'
console.log(+s) // 123(Number类型)
3. 位操作符
位操作符基于最基本的格式,直接在内存中操作表示数值的位。位操作符不直接操作64位的值,而是将64位的值转换为32位的整数,然后执行操作,也就是说小数部分被忽略。
对于有符号的整数,前31位表示整数的值,第32位表示符号,0表示整数,1表示负数。
其中正数以纯二进制保存,例如,数值18的二进制表示就是 0000 0000 0000 0000 0000 0000 0001 0010,简写10010,这是五个有效位,决定了实际的值。( 2^4 * 1 + 2^3 * + 2^2 0 + 2^11 +2^0*0 = 16 = 2 = 18)。
负数同样以二进制存储,不过是二进制补码。计算步骤如下:
这里以18为例
// 先求负数绝对值对应的二进制
0000 0000 0000 0000 0000 0000 0001 0010
// 然后求其反码,即0 、 1互换
1111 1111 1111 1111 1111 1111 1110 1101
// 最后加1
1111 1111 1111 1111 1111 1111 1110 1101
1
---------------------------------------
1111 1111 1111 1111 1111 1111 1110 1110
js 会尽量隐藏这样的信息,以更合理的防止展现,这里的转化就理解了二进制补码并合理显示。
var num = -18
console.log(num.toString(2)) // -10010
对于NaN和Infinity应用位操作符时会当成0处理,其他非数值会先使用Number函数转化为数值,在进行位操作。
1.按位非(NOT)
按位非就是返回数值的反码,用波浪号~表示,聪明的朋友肯定发现了,按位非就是负数操作的第一步,所以倒推的话,按位非就是操作数的负数减1。
var num1 = 25
console.log(~num1) // -26
2.按位与(AND)
按位与有两个操作数,符号是&,本质上就是两个数值的每一位对齐,然后执行AND操作。
| 第一个数值的位 | 第二个数值的位 | 结果 |
|---|---|---|
| 1 | 1 | 1 |
| 1 | 0 | 0 |
| 0 | 1 | 0 |
| 0 | 0 | 0 |
console.log(25 & 3); // 1
// 具体执行结果
0000 0000 0000 0000 0000 0000 0001 1001 // 25
0000 0000 0000 0000 0000 0000 0000 0011 // 3
---------------------------------------
0000 0000 0000 0000 0000 0000 0000 0001 // 结果为1
3.按位非(OR)
按位或也有两个操作数,符号是|,本质也是两个数每一位对齐,然后执行或操作。
| 第一个数值的位 | 第二个数值的位 | 结果 |
|---|---|---|
| 1 | 1 | 1 |
| 1 | 0 | 1 |
| 0 | 1 | 1 |
| 0 | 0 | 0 |
console.log(25 | 3); // 1
// 具体执行结果
0000 0000 0000 0000 0000 0000 0001 1001 // 25
0000 0000 0000 0000 0000 0000 0000 0011 // 3
---------------------------------------
0000 0000 0000 0000 0000 0000 0001 1011 // 结果为27
按位异或(XOR)
按位异或也有两个操作数,符号是^,本质也是两个数每一位对齐,然后执行异或操作。它与按位或的区别是对应为上只有一个1时才返回1。
| 第一个数值的位 | 第二个数值的位 | 结果 |
|---|---|---|
| 1 | 1 | 0 |
| 1 | 0 | 1 |
| 0 | 1 | 1 |
| 0 | 0 | 0 |
console.log(25 ^ 3); // 1
// 具体执行结果
0000 0000 0000 0000 0000 0000 0001 1001 // 25
0000 0000 0000 0000 0000 0000 0000 0011 // 3
---------------------------------------
0000 0000 0000 0000 0000 0000 0001 1010 // 结果为26
左移
左移操作符由两个小于号(<<)表示,它会将数值的所有位向左移动指定的位数。
var foo = 2 // 二进制的码为10
var bar = foo << 5 // 等于二进制的1000000,10进制的64
左移后右侧的空位由0补齐,并且左移不会影响操作数符号。
有符号右移
和左移类似,只不过向右移动,缺的位用符号位的值补齐,不影响操作数符号。
var foo = 64 // 二进制的码为1000000
var bar = foo >> 5 // 等于二进制的10,10进制的2
无符号右移
无符号右移用>>>表示,会把所有位向右移动,然后用0补充空位,对于正数来说和有符号右移没区别,对于负数:
var foo = -64 // 二进制的码为1111 1111 1111 1111 1111 1111 1100 0000
var bar = foo >> 5 // 等于二进制的0000 0111 1111 1111 1111 1111 1111 1110,10进制的134217726