ECMAScript 位运算符

位运算符是在数字底层(即表示数字的 32 个数位)举办操作的。

老生常谈整数

ECMAScript
整数有三种档次,即有符号整数(允许用正数和负数)和无符号整数(只同意用正数)。在
ECMAScript 中,所有整数字面量默许都是有号子整数,那代表什么样呢?

有标志整数使用 31 位表示整数的数值,用第 32 位表示整数的标记,0
表示正数,1 表示负数。数值范围从 -2147483648 到 2147483647。

可以以两种区其他艺术存储二进制方式的有号子整数,一种用于存储正数,一种用于存储负数。正数是以真二进制格局储存的,前
31 位中的每一位都代表 2 的幂,从第 1 位(位 0)开始,表示
20,第 2 位(位 1)表示 21。没用到的位用 0
填充,即忽略不计。例如,下图体现的是数 18 的表示法。

图片 1

18 的二进制版本只用了前 5
位,它们是这几个数字的实用位。把数字转换成二进制字符串,就能看到有效位:

var iNum = 18;
alert(iNum.toString(2));    //输出 "10010"

那段代码只输出 “10010”,而不是 18 的 32
位表示。其余的数位并不紧要,因为仅使用前 5
位即可确定那个十进制数值。如下图所示:

图片 2

负数也蕴藏为二进制代码,可是使用的款式是二进制补码。统计数字二进制补码的手续有三步:

  1. 规定该数字的非负版本的二进制表示(例如,要总计-18的二进制补码,首先要规定 18 的二进制表示)
  2. 求得二进制反码,即要把 0 替换为 1,把 1 替换为 0
  3. 在二进制反码上加 1

要确定 -18 的二进制表示,首先必须得到 18 的二进制表示,如下所示:

0000 0000 0000 0000 0000 0000 0001 0010

接下去,计算二进制反码,如下所示:

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 的二进制表示即 1111 1111 1111 1111 1111 1111 1110
1110。记住,在处理有号子整数时,开发者无法访问 31 位。

诙谐的是,把负整数转换成二进制字符串后,ECMAScript
并不以二进制补码的格局浮现,而是用数字相对值的专业二进制代码前边加负号的花样出口。例如:

var iNum = -18;
alert(iNum.toString(2));    //输出 "-10010"

那段代码输出的是 “-10010″,而非二进制补码,那是为防止访问位
31。为了省事,ECMAScript
用一种不难的办法处理整数,使得开发者不必关怀它们的用法。

一边,无符号整数把最后一位作为另一个数位处理。在那种情势中,第 32
位不表示数字的记号,而是值
231。由于这么些附加的位,无符号整数的数值范围为 0 到
4294967295。对于小于 2147483647
的平头来说,无符号整数看来与有号子整数一样,而高于 2147483647
的平头则要选拔位 31(在有标志整数中,这一位一连 0)。

把无符号整数转换成字符串后,只回去它们的卓有成效位。

注意:所有整数字面量都默许存储为有号子整数。唯有 ECMAScript
的位运算符才能成立无符号整数。

位运算 NOT

位运算 NOT 由否定号(~)表示,它是 ECMAScript
中为数不多的与二进制算术有关的运算符之一。

位运算 NOT 是三步的处理进度:

  1. 把运算数转换成 32 位数字
  2. 把二进制数转换成它的二进制反码
  3. 把二进制数转换成浮点数

例如:

var iNum1 = 25;        //25 等于 00000000000000000000000000011001
var iNum2 = ~iNum1;    //转换为 11111111111111111111111111100110
alert(iNum2);       //输出 "-26"

位运算 NOT 实质上是对数字求负,然后减 1,由此 25 变
-26。用上面的艺术也得以博得一致的不二法门:

var iNum1 = 25;
var iNum2 = -iNum1 -1;
alert(iNum2);   //输出 -26

位运算 AND

位运算 AND
由和号(&)表示,直接对数字的二进制格局举行演算。它把各样数字中的数位对齐,然后用上面的平整对同样义务上的四个数位举行AND 运算:

第一个数字中的数位 第二个数字中的数位 结果
1 1 1
1 0 0
0 1 0
0 0 0

譬如说,要对数字 25 和 3 进行 AND 运算,代码如下所示:

var iResult = 25 & 3;
alert(iResult); //输出 "1"

25 和 3 进行 AND 运算的结果是 1。为啥?分析如下:

 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 中,唯有一个数位(位 0)存放的都是
1,由此,其他数位生成的都是 0,所以结果为 1。

位运算 OR

位运算 OR
由符号(|)表示,也是一向对数字的二进制格局展开演算。在测算每位时,OR
运算符拔取下列规则:

第一个数字中的数位 第二个数字中的数位 结果
1 1 1
1 0 1
0 1 1
0 0 0

依然选用 AND 运算符所用的事例,对 25 和 3 举办 OR 运算,代码如下:

var iResult = 25 | 3;
alert(iResult); //输出 "27"

25 和 3 进行 OR 运算的结果是 27:

25 = 0000 0000 0000 0000 0000 0000 0001 1001
 3 = 0000 0000 0000 0000 0000 0000 0000 0011
--------------------------------------------
OR = 0000 0000 0000 0000 0000 0000 0001 1011

可以看到,在七个数字中,共有 4 个数位存放的是
1,那个数位被传送给结荚。二进制代码 11011 对等 27。

位运算 XOR

位运算 XOR 由符号(^)表示,当然,也是直接对二进制形式展开演算。XOR
分歧于 OR,当唯有一个数位存放的是 1 时,它才重返 1。真值表如下:

第一个数字中的数位 第二个数字中的数位 结果
1 1 0
1 0 1
0 1 1
0 0 0

对 25 和 3 进行 XOR 运算,代码如下:

var iResult = 25 ^ 3;
alert(iResult); //输出 "26"

25 和 3 举办 XOR 运算的结果是 26:

 25 = 0000 0000 0000 0000 0000 0000 0001 1001
  3 = 0000 0000 0000 0000 0000 0000 0000 0011
---------------------------------------------
XOR = 0000 0000 0000 0000 0000 0000 0001 1010

可以观望,在五个数字中,共有 4 个数位存放的是
1,那一个数位被传送给结荚。二进制代码 11010 出色 26。

左移运算

左移运算由八个低于号表示(<<)。它把数字中的所有数位向左移动指定的多少。例如,把数字
2(等于二进制中的 10)左移 5 位,结果为 64(等于二进制中的 1000000):

var iOld = 2;      //等于二进制 10
var iNew = iOld << 5; //等于二进制 1000000 十进制 64

留意:在左移数位时,数字左边多出 5 个空位。左移运算用 0
填充这几个空位,使结果变成完全的 32 位数字。

图片 3

在意:左移运算保留数字的标记位。例如,即使把 -2 左移 5 位,得到的是
-64,而不是 64。“符号如故蕴藏在第 32 位中呢?”是的,但是那在 ECMAScript
后台进行,开发者不可以一贯访问第 32
个数位。纵然输出二进制字符串方式的负数,显示的也是负号形式(例如,-2
将显得 -10。)

有号子右移运算

有号子右移运算符由三个超过号表示(>>)。它把 32
位数字中的所有数位全部右移,同时保留该数的标记(正号或负号)。有标志右移运算符恰好与左移运算相反。例如,把
64 右移 5 位,将变成 2:

var iOld = 64;     //等于二进制 1000000
var iNew = iOld >> 5; //等于二进制 10 十进制 2

一律,移动数位后会造成空位。这次,空位位于数字的左侧,但位于符号位之后。ECMAScript
用符号位的值填充这几个空位,成立完整的数字,如下图所示:

图片 4

无符号右移运算

无符号右移运算符由多少个高于号(>>>)表示,它将无符号 32
位数的具有数位整体右移。对于正数,无符号右移运算的结果与有号子右移运算一样。

用有号子右移运算中的例子,把 64 右移 5 位,将变成 2:

var iOld = 64;     //等于二进制 1000000
var iNew = iOld >>> 5; //等于二进制 10 十进制 2

对于负数,情状就不相同了。

无符号右移运算用 0
填充所有空位。对于正数,那与有记号右移运算的操作一样,而负数则被看成正数来拍卖。

由于无符号右移运算的结果是一个 32
位的正数,所以负数的无符号右移运算取得的连年一个相当大的数字。例如,假若把
-64 右移 5 位,将得到 134217726。如何赢得那种结果的吗?

要完结那或多或少,须要把那么些数字转换成无符号的对等格局(即使该数字本身仍旧有标志的),可以通过以下代码获得那种样式:

var iUnsigned64 = -64 >>> 0;

下一场,用 Number 类型的 toString() 获取它的真正的位代表,选取的基为 2:

alert(iUnsigned64.toString(2));

那将生成 11111111111111111111111111000000,即有符号整数 -64
的二进制补码表示,可是它非常无符号整数 4294967232。

是因为那种原因,使用无符号右移运算符要小心。