注意: 本文章为 《重学js之JavaScript高级程序设计》系列第三章第二部分【操作符】。
关于《重学js之JavaScript高级程序设计》是重新回顾js基础的学习。
1. 操作符
用于描述一组可以操作数据值的概念叫做操作符。包括 算术操作符(加号和减号)、位操作符、关系操作符和相等操作符。ES的操作符和其他不同的在于它能够适用于很多值,如:字符串、数字值、布尔值、甚至对象。在应用于对象的时候,需要调用对象的 valueOf() 和 toString()方法。
1.1 一元操作符
1.1.1 递增和递减操作符
分为两种类型:前置和后置型,前置位于要操作的变量之前。后置则在要操作的变量之后。如下:
var age = 29
++age // 30
等于
age = age + 1
--age // 28
等于
age = age - 1
注意:执行前置递增或递减的时候,变量的值都是在语句被求值以前改变的。
var age = 29
var a = --age + 2
age // 28
a // 30
// 由于前置递增和递减与执行语句的优先级相等,
所以整个语句会被从左到右求值。
var num1 = 2
var num2 = 20
var num3 = --num1 + num2 // 21
var num4 = num1 + ++num3 // 23
后置型递增和递减操作语法不变,只不过由前面放到了后面,而且最重要的是:后置型递增和递减的操作都是在变量执行之后在操作的。如下:
var num = 3
var age = 4
num-- + age-- // 7
num // 2
age // 4
总结:
以上4个操作符对任何值都适用,不限于数字还可以用于字符串、布尔值、浮点数值和对象,规则如下:
1、应用于数字字符的字符串时候,先将其转换为数字值,
在执行加减 1 的操作,字符串变量变成数值变量。
2、应用于不包含有效数字的字符串时,将其变量的值设置
位NaN,字符串变量变成数值变量
3、用于布尔值false的时候,将其转换为0,在执行加减1的
操作,布尔值变成数值
4、用于布尔值true的时候,将其转换为1,在执行加减1的操
作,布尔值变成数值
5、用于浮点数,执行加减1的操作
6、用于对象,先调用对象的valueOf()方法,如果返回的结果
是NaN在调用toString()方法,对象的变量变成数值变量。
上面的说明如下:
var s1 = '2'
var s2 = 'z'
var s3 = false
var s4 = 1.1
var s5 = {
valueOf: function(){
return -1
}
}
s1++ // 3
s2++ // NaN
s3++ // 1
s4-- // 0.10000000000009
s5-- // -2
1.1.2 一元加和减操作符
var num = 25
num = +num // 25
num = -num // -25
注意:还是遵循之前的规则,对于字符串的变量使用加减操作符 则变成 NaN 其他的则相应变成指定规则的数值。
一元加减操作符主要用于基本的算术运算,也可以用于转换数据类型。
1.2 位操作符
位操作符是用于内存中表示数值的位来操作数值。ES中所有的值都是按照64位格式存储,但位操作符并直接操作64位值,而是先将64位的值转换成32位整数,然后执行操作,最后在将结果转换位64位。
对于有符号的整数,32位中的前31位用于表示整数的值,第32位表示数值的符号,0表示整数,1表示负数。这个表示符号的位叫做符号位。符号位的值决定了其他位数值的格式。其中,正数以纯二进制格式存储,31位中的每一位都表示2的幂,第一位表示 2的0次方以此类推。没有用到的用0填充忽略不计。也就是2进制表示法。
负数同样可以以二进制存储,但是使用的格式是二进制补码,计算一个数值的二进制补码步骤如下:
1、求这个数值绝对值的二进制码
2、求二进制反码
3、得到的二进制反码 +1
如下:求 -18的二进制码
0000 0000 0000 0000 0000 0001 0010
求反码 0 1 互换
1111 1111 1111 1111 1111 1110 1101
然后 加 1
1111 1111 1111 1111 1111 1110 1110
在ES中,ES会尽力向我们隐藏所有这些信息,也就是说,在二进制字符串形式输出一个负数时,我们看到的只是这个负数绝对值的二进制码之前加了一个负号,如下:
var num = -18
num.toString(2) // '-10010'
注意:默认情况下,ES中所有的整数都是有符号整数,当然也存在无符号整数,对于无符号整数来说,第32位不再表示符号,因为无符号整数只能是正数,而且无符号整数的值可以更大,因为多出来的一位不再表示符号,可以用来表示数值。
在ES中当对应数值应用位操作符时,后台会发生如下转换过程:64位的数值被转换成32位数值,然后执行位操作,最后再将32位数值转换回64位数值。这样表面上看起来好像是在操作 32 位数值,另外有个问题,这样的操作导致在特殊值 如 NaN 和 Infinity值应用位操作的时候,这两个值会被当成0来处理。
注意:如果对非数值进行位操作符,那么会先使用 Number() 函数将该值转换为一个数值,在应用位操作,得到的结果是一个数值。
- 按位非(NOT)
按位非操作符由一个波浪线(~)表示,执行按位非的结果就是返回数值的反码并减一,如下:
var num = 25 // 二进制 0001 1001
var num1 = ~num // 二进制 1110 0110
// -26
- 按位与
按位与操作符由一个和字符号(&)表示,它有两个操作符数。从本质上来讲,按位与操作就是将两个数值的每一位对齐,根据以下规则,对相同位置上的两个数执行AND操作:
结果:全1才为1,有0返回0
第一个数值的位 | 第二个数值的位 | 结果 |
---|---|---|
1 | 1 | 1 |
1 | 0 | 0 |
0 | 1 | 0 |
0 | 0 | 0 |
- 按位或(OR)
按位或由一个竖线符号(|)表示,同样也有两个操作数,操作结果遵循下表。
第一个数值的位 | 第二个数值的位 | 结果 |
---|---|---|
1 | 1 | 1 |
1 | 0 | 1 |
0 | 1 | 1 |
0 | 0 | 0 |
结果:有1返回1,全0返回0
- 按位异或(XOR)
按位异或操作符由一个插入符号 (^)表示,也是两个操作数,结果遵循下表:
第一个数值的位 | 第二个数值的位 | 结果 |
---|---|---|
1 | 1 | 0 |
1 | 0 | 1 |
0 | 1 | 1 |
0 | 0 | 0 |
结果:两个数只有1个为1的时候才返回1,同时为1或同时为0 则返回0
- 左移
// 将数值2向左移动5位,结果就是64位
var oldnum = 2 // 二进制 10
var newnum = oldnum << 5 // 二进制 1000000 , 十进制 64
注意: 在向左移位后,原数值的右侧多出了 5 个空位,左移操作
会以0来填充这些空位,以便得到的结果是一个完整的32位的二进制数。
- 有符号的右移
有符号的右移操作符由两个大于号(>>)表示,这个操作符会将数值向右移动,但保留符号位(即正负号标记),有符号的右移操作与左移操作恰好相反,即如果将64向右移动5位,结果将变回2.如下:
var oldnum = 64 // 二进制 1000000
var newnum = oldnum >> 5 // 二进制 10 2
注意:在移位的过程中,原数值也会出现空位,只不过这次
空位出现在原数值的左侧、符号位的右侧,这时候ES就会用
符号位的值来填充所有的空位,以便得到一个完整的值。
- 无符号右移
无符号右移操作符右三个大于号(>>>)组成,这个操作符会将数值的所有32位都向右移动,对于正数来说,无符号右移的结果与有符号右移相同,如下
var oldnum = 64 // 二进制 1000000
var newnum = oldnum >>> 5 // 二进制 10 十进制 2
注意:在负数下情况就不一样了,首先,无符号右移是以0来填充空位,而不是像有符号右移那样以符号位来填充空位。所以,对正数的无符号右移与有符号右移结果相同,但对负数的结果就不一样了。其次无符号右移操作符会把负数的二进制码当成正数的二进制码。而且,由于负数以其绝对值补码形式表示,因此就会导致无符号右移后的结果非常之大。如下:
var oldnum = -64 // 二进制 11111111111111111111111111000000
var newnum = oldnum >>> 5 // 十进制 134217726