文章
先来个列表
操作符 用法 描述
按位与 a & b 如果两个操作数对应位都是 1 的话则在该位返回 1。
按位或 a | b 如果两个操作数对应位都是 0 的话则在该位返回 0。
按位异或 a ^ b 如果两个操作数对应位只有一个 1 的话则在该位返回 1。
求反 ~ a 反转操作数的每一位。
左移 a << b 将 a 的二进制形式左移 b 位。右面的空位补零。
算术右移 a >> b 将 a 的二进制形式右移 b 位。忽略被移出的位。
逻辑右移 a >>> b 将 a 的二进制形式右移 b 位。忽略被移出的位,左侧补入 0。
先知道一点:
数据在内存中是以二进制形式存放的。数值是以补码表示的。一个正数的补码和其原码的形式相同。
而负数的补码方式是将其绝对值的二进制形式“按位求反再加1”
二元位操作符
用作测试的函数
扔到console里直接用即可
var hex10to2 = function (o){
//鉴于parseInt('0101') 与 parseInt(0101) 的不同结果(纠结,各浏览器应该不同,待测试),
//在您输入的时候请直接输入8进制数时,请直接输入数字(0101)
//测试用,所以先只支持整数
if(parseInt(o)){
return parseInt(o).toString(2);
} else{
console.log('参数不正确,正确的参数为:1.整数 2.合法字符串(如"123","0123","0x123")');
}
}
//忽略符号处理
var hex2to10 = function(str){
//TODO:判断是否只包括 1 , 0
return parseInt(str,2);
}
//两个函数的合并作业待做
我还比较熟悉的: &,|,^
三种,举例如下:
65 & 32 结果为 0
1000001
100000
-------
0000000
65 | 32 结果为 97
1000001
100000
-------
1100001
65 ^ 32 结果为 97
1000001
100000
-------
1100001
另外~很少用,也不熟悉
详细说明
取反运算符~对运算数按位取反,将运算数各位值由1变为0,或由0变为1.因为计算机中数值以带符号位二进制表示,所以取反后,最高位符号位发生变化。
32按位取反后结果为(-33)。我们采用32的8位二进制形式:
hex10to2(32) => 100000 补全得:00100000
00100000 按位取反为 11011111,这是一个补码形式,最高位为符号位。将该补码再求补(符号位保持不变,其他位按位取反,最后加1),得到10100001,该值是带符号的真值
hex2to10('100001'); //33
加个负号得:-33
另外:
97 & -33 //65
将 -33(10100001)符号位保持不变,其他位按位取反,最后加1,为:11011111
01100001
11011111
--------
01000001
hex2to10('01000001'); //65
正如你看到的,原码和补码是可逆的, 写成
97 & ~32
更一目了然一些,因为我只需要去掉从右向左数的第6个 1,那个1 => 2的(6-1)次方,所以 &
一下 ~32
即可
位操作进行加减运算
... 64 32 16 8 4 2 1
... 7 6 5 4 3 2 1
如果想让第x位变成 1,也就是加上 2 的 x-1
次方(如果那位不是1的话),令 y = 2 的 x-1
次方
x | y
如果想让第x位变成 0,也就是减去 2 的 x-1
次方(如果那位不是0的话),令 y = 2 的 x-1
次方
x & ~ y
有意思的实现
手动大小写
因为javascript已经实现了(toUpperCase() and toLowerCase())
function isString(value){return typeof value == 'string';}
var manualLowercase = function(s) {
return isString(s)
? s.replace(/[A-Z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) | 32);})
: s;
};
var manualUppercase = function(s) {
return isString(s)
? s.replace(/[a-z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) & ~32);})
: s;
};
奇偶数判断
function isNumber(value){return typeof value == 'number';}
//利用 0 或 1 对 1 的 & 运算都是原数值,可得:
var isOdd = function(num){ //奇数
if(isNumber(num)){
return num & 1 ? true : false;
} else{
return false;
}
}
var isEven = function(num){ //偶数
if(isNumber(num)){
return num & 1 ? false : true;
} else{
return false;
}
}
移位操作符
移位操作符需要两个操作数:第一个是要进行移位的数值,第二个指定要对第一个数移位的数目。移位的方向由使用的操作符决定。
移位操作符将把两个操作符转换为 32 位整型数值,并返回与左操作数类型相同的结果。
<< (左移)
该操作符将把第一个操作数向左移若干位。移出的位将被忽略。右侧空位补零。 例如,9<<2 结果为 36,因为 1001 向左移两位变成 100100,这是 36。快捷算法:9 * (2的移位次方)
>> (算术右移)
该操作符将把第一个操作数向右移若干位。移出的位将被忽略。左侧的空位补上与原来最左面位相同的值。 例如,9>>2 结果为 2,因为 1001 右移两位变成 10,这是 2。。快捷算法:9 / (2的移位次方)
反之,-9>>2 结果为 -3,因为要考虑到符号位。
9在计算机中表示为(我们采用9的8位二进制形式)
00001001
则 -9,为:
10001001
重复上面的算法:符号位保持不变,其他位按位取反,最后加1,得到 -9 在计算机中的表示
11110111
算数右移两位 => 补1
11111101
重复补码算法
10000011
得到 -3
>>> (逻辑右移)
该操作符将把第一个操作数向右移若干位。移出的位将被忽略。左侧的空位补零。 例如,19>>>2 结果为 4,因为 10011 右移两位变成 100,这是 4。对于非负数,算术右移和逻辑右移结果相同。
那么负数呢?
-9>>2 结果为 ?
9在计算机中表示为(我们采用9的8位二进制形式)
00001001
则 -9,为:
10001001
重复上面的算法:符号位保持不变,其他位按位取反,最后加1,得到 -9 在计算机中的表示
11110111
逻辑右移两位 => 补0
00111101
因为变成正数了,所以不用重复补码算法了
计算机采用的是32位二进制形式,所以
0011...1101 //中间是30个1
得到 1073741821
hex10to2(1073741821) //111111111111111111111111111101
"111111111111111111111111111101".length //30,略去了前面两个0