上一篇文章我们了解了加性操作符、关系操作符、相等操作符和条件操作符,这一篇文章讲解赋值操作符、逗号操作符和位操作符。
赋值操作符用一个等号表示(=)。作用就是把右侧的值赋给左侧的变量,如下面代码所示
var a=1; //将1赋给变量a
赋值操作符还可以配合加性操作符或乘性操作符一起使用,如下面的例子
var a=1;
a+=2; //等同于a=a+2
a-=2; //等同于a=a-2
a*=2; //等同于a=a*2
a/=2; //等同于a=a/2
a%=2; //等同于a=a%2
这样做只是为了简化代码的写法,并不能提高性能。
逗号操作符最常用的做法就是在一条语句中声明多个变量,如下面代码所示
var a=1,b=2,c=3;
除此之外,逗号操作符也可以用来赋值,如下面代码所示
var a=(1,2,3) //a被最终赋值为3
但是以上做法在实际开发中并不常用。
以下内容节选自《JavaScript高级编程》
位操作符用于在最基本的层次上,即按内存中表示数值的位来操作数值。ECMAScript中的所有数值都以IEEE-754 64 位格式存储,但位操作符并不直接操作64位的值。而是先将64位的值转换成32位的整数,然后执行操作,最后再将结果转换回64位。对于开发人员来说,由于64位存储格式是透明的,因此整个过程就像是只存在32位的整数一样。
对于有符号的整数,32位中的前31位用于表示整数的值。第32位用于表示数值的符号:0表示正数,1表示负数。这个表示符号的位叫作符号位,符号位的值决定了其他位数值的格式。其中,正数以纯二进制格式存储,31位中的每一位都表示2的幂。第一位(叫做位0)表示2的0次方,第二位表示2的1次方,以此类推。没有用到的位以0填充,即忽略不计。例如:数值18的二进制表示是00000000000000000000000000010010,或更简洁的10010.这是5个有效位,这5位本身就决定了实际值。
1 0 0 1 0
(2的4次方*1)+(2的3次方*0)+(2的2次方0)+(2的1次方*1)+(2的0次方*0)
负数同样以二进制码存储,但是用的格式是二进制补码。计算一个数值的二进制补码,需要经过下列3个步骤:
1、求这个数值绝对值的二进制码(例如,要求-18的二进制补码,先求18的二进制码)
2、 求二进制反码,即将0替换为1,将1替换为0;
3、 得到的二进制反码加1.
要根据这3个步骤求得-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
这样,就求得了-18的二进制表示,即11111111111111111111111111101110。
要注意的是,在处理有符号整数时,是不能访问位31的。
ECMAScript会尽力向我们隐藏所有这些信息。换句话说,在以二进制字符串形式输出一个负数时,我们看到的只是这个负数绝对值二进制码前面加上了一个负号。 如:
var num=-18;
alert(num.toString(2));//"-10010"
要把数值-18转换为二进制字符串时,得到的结果是“-10010”。这说明转换过程理解了二进制补码并将其以更合乎逻辑的形式展示出来。
默认情况下,ECMAScript中的所有整数都是有符号整数。不过,当然也存在无符号整数。对于无符号整数来说,第32位不再表示符号,因为无符号整数只能是正数。而且,无符号整数的值可以更大,因为多出的一位不再表示符号,可以用来表示数值。
在ECMAScript中,当对数值应用位操作符时,后台会发生如下转换过程:64位的数值被转换成32位数值,然后执行位操作,最后再将32位的结果转换回64位数值。这样,表面上看起来就像是在操作32位数值,就跟在其他语言中以类似方式执行二进制操作一样。但这个转换过程也导致了一个严重的副效应,即在对特殊的NaN和Infinity值应用位操作时,这两个值都会被当成0来处理。
如果对非数值应用位操作符,会此案使用Number()函数将该值转换为一个数值(自动完成),然后再应用位操作。得到的结果将是一个数值。
按位非操作符由一个波浪线~表示,执行按位非的结果就是返回数值的反码。 按位非是ECMAScript操作符中少数几个与二进制计算有关的操作符之一。如:
var num1=25;//二进制 00000000000000000000000000011001
var num2=~mun1;//二进制11111111111111111111111111100110
alert(num2);//-26
这里,对25执行按位非操作,结果得到了-26. 这也验证了按位非操作的本质:操作数的负值减1. 因此,下面的代码也能得到相同的结果:
var num1=25;
var num2=-num1-1;
alert(num2);//"-26"
虽然以上代码也能返回同样的结果,但由于按位非是在数值表示的最底层执行操作,因此速度更快。
按位与操作符有一个和号字符&表示,它有两个操作符数。从本质上讲,按位与操作就是将两个数值的每一位对齐,然后根据下表中的规则,对相同位置上的两个数执行AND操作:
第一个数值的位 | 第二个数值的位 | 结果 |
1 | 1 | 1 |
1 | 0 | 0 |
0 | 1 | 0 |
0 | 0 | 0 |
简而言之,按位与操作只在两个数值的对应为都是1时才返回1,任何一位是0,结果都是0。下面看一个对25和3执行按位与操作的例子:
var result=25&3;
alert(result);//1
可见,对25和3执行按位与操作的结果是1.为什么呢?请看其d底层操作:
25 = 0000 0000 0000 0000 0000 0000 0001 1001
3 = 0000 0000 0000 0000 0000 0000 0000 0011
------------------------------------------------------------------
AND = 0000 0000 0000 0000 0000 0000 0000 0001
原来,25和3的二进制码对应位上只有一位同时是1,而其他位的结果自然都是0,因此最终结果等于1.
按位或操作符有一个竖线符号|表示,同样也有两个操作数。按位或操作遵循下面这个真值表。
第一个数值的未 第二个数值的位 结果
1 1 1
1 0 1
0 1 1
0 0 0
由此可见,按位或操作在有一个位是1的情况下就返回1,而只有在两个为都是0的情况下才返回0.如果在前面按位与的例子中对25和3执行按位或操作,则代码如下所示:
var result=25 | 3;
alert(result);//27
25与23按位或的结果是27:
25 = 0000 0000 0000 0000 0000 0000 0000 0001 1001
3 = 0000 0000 0000 0000 0000 0000 0000 0000 0011
------------------------------------------------------------
OR = 0000 0000 0000 0000 0000 0000 0000 0001 1011
这两个数值的都包含4个1,因此可以把每个1直接放到结果中。二进制码11011等于十进制值27.
按位异或操作符由一个插入符号^表示,也有两个操作数。以下是按位异或的真值表。
第一个数值的为 | 第二个数值的位 | 结果 |
1 | 1 | 0 |
1 | 0 | 1 |
0 | 1 | 1 |
0 | 1 | 0 |
按位异或与按位或的不同之处在于,这个操作在两个数值对应位上只有一个1时才返回1,如果对应的两位都是1或都是0,则返回0.
对25和3执行按位异或操作的代码如下所示:
var result = 25^3;
alert(result);//26
25与3按位异或的结果是26,其底层操作如下所示:
25 = 0000 0000 0000 0000 0000 0000 0000 0001 1001
3 = 0000 0000 0000 0000 0000 0000 0000 0000 0011
------------------------------------------------------------
XOR=0000 0000 0000 0000 0000 0000 0000 0001 1010
左移操作符由两个小于号(<<)表示,这个操作符会将数值的所有位向左移动指定的位数,例如,如果将数值2(二进制码为10)向左移动5位,结果就是64(二进制码为1000000),代码如下
var oldnum = 2 // 二进制 10
var newnum = oldnum << 5 // 二进制 1000000 , 十进制 64
注意: 在向左移位后,原数值的右侧多出了 5 个空位,左移操作会以0来填充这些空位,以便得到的结果是一个完整的32位的二进制数。 左移不会影响操作数的符号位,如果将-2左移5位,结果为-64,而非64。
有符号的右移操作符由两个大于号(>>)表示,这个操作符会将数值向右移动,但保留符号位(即正负号标记),有符号的右移操作与左移操作恰好相反,即如果将64向右移动5位,结果将变回2
var oldnum = 64 // 二进制 1000000
var newnum = oldnum >> 5 // 二进制 10 2
注意:在移位的过程中,原数值也会出现空位,只不过这次 空位出现在原数值的左侧、符号位的右侧,这时候ES就会用 符号位的值来填充所有的空位,以便得到一个完整的值。
无符号右移操作符右三个大于号(>>>)组成,这个操作符会将数值的所有32位都向右移动,对于正数来说,无符号右移的结果与有符号右移相同,如果将64无符号右移5位,结果还是2:
var oldnum = 64 // 二进制 1000000
var newnum = oldnum >>> 5 // 二进制 10 十进制 2
注意:在负数下情况就不一样了,首先,无符号右移是以0来填充空位,而不是像有符号右移那样以符号位来填充空位。所以,对正数的无符号右移与有符号右移结果相同,但对负数的结果就不一样了。其次无符号右移操作符会把负数的二进制码当成正数的二进制码。而且,由于负数以其绝对值补码形式表示,因此就会导致无符号右移后的结果非常之大。如下:
var oldnum = -64 // 二进制 11111111111111111111111111000000
var newnum = oldnum >>> 5 // 十进制 134217726
本篇文章讲解了JavaScript中的赋值操作符、逗号操作符和位操作符,至此,JavaScript的操作符部分就已经全部讲解完成了,后面的篇章将继续讲解JavaScript中的语句。