JavaScript位操作符

231 阅读5分钟

ECMAScriptt中所有的数值都以IEEE-754 64位格式储存,但是位操作符并不直接操作64位的值。而是先将64位的值转换成32位的整数,然后再执行操作,最后再将结果转换回64位。对于开发人员来说,由于64位储存格式是透明的,所以整个过程就像是只存在32位的整数一样。

数值的表示

对于所有有符号的整数,32位中前31位表示整数的值。第32位表示数值的符号,0表示正数,1表示负数,符号位的值决定了其他位数值的格式。

正数

正数以存二进制格式存储

比如18的二进制表示是

0000 0000 0000 0000 0000 0000 0001 0010
//其中有效为为前5位、没有用到的位以0填充
10010

负数

负数使用的格式是二进制补码,计算一个数值的二进制补码,需要下面几个步骤(以-18为例)

1.求这个数值的绝对值的二进制码

//18的二进制码
0000 0000 0000 0000 0000 0000 0001 0010

2.二进制反码,将0替换成1,将1替换成0

//18的二进制反码
1111 1111 1111 1111 1111 1111 1110 1101

3.二进制反码加1

//18的二进制反码加1
1111 1111 1111 1111 1111 1111 1110 1110

操作符

按位非(~)

按位非返回的是数值的反码

//一个数的负数=一个数的二进制反码+1
//一个数的二进制反码=一个数的负数-1
let a=18
let b=~a//-19

常用方法

取整,类似于parseInt

~~2.2222 //2

按位与(&)

将两个数的每一位对齐,只有在对应位置上都是1的时候才返回1

//18的二进制码
0000 0000 0000 0000 0000 0000 0001 0010
//3的二进制码
0000 0000 0000 0000 0000 0000 0000 0011
//18&3
0000 0000 0000 0000 0000 0000 0000 0010

let a=18
let b=3
let c=a&b //2

常用方法

判断奇偶数

num&1
//如果结果是1那么是奇数
//如果是0那么是偶数

按位或(|)

将两个数的每一位对齐,在对应位置上只要有一个1的情况下就返回1

//18的二进制码
0000 0000 0000 0000 0000 0000 0001 0010
//3的二进制码
0000 0000 0000 0000 0000 0000 0000 0011
//18|3
0000 0000 0000 0000 0000 0000 0001 0011

let a=18
let b=3
let c=a|b //19

按位异或(^)

将两个数的每一位对齐,在对应位置上只有一个1的情况下才返回1

//18的二进制码
0000 0000 0000 0000 0000 0000 0001 0010
//3的二进制码
0000 0000 0000 0000 0000 0000 0000 0011
//18^3
0000 0000 0000 0000 0000 0000 0001 0001

let a=18
let b=3
let c=a^b //17

常用方法

完成数值交换

let a=1
let b=2
a ^= b
b ^= a
a ^= b
console.log(a) // 2
console.log(b) // 1

左移(<<)

将一个数值的所有位向左移动指定的位数

//18的二进制码
0000 0000 0000 0000 0000 0000 0001 0010
//18<<5
0000 0000 0000 0000 0000 0010 0100 0000

let a=18
18<<5//576
//但是有可能会出现改变符号位的情况,以及超出位数的情况
//1的二进制
0000 0000 0000 0000 0000 0000 0000 0001
1<<31
1000 0000 0000 0000 0000 0000 0000 0000
1<<32 
0000 0000 0000 0000 0000 0000 0000 0001

有符号右移(>>)

保留符号位,从第31位开始向右移指定位数

//576的二进制码
0000 0000 0000 0000 0000 0010 0100 0000
//576>>5
0000 0000 0000 0000 0000 0000 0001 0010

let a=576
576>>5//18

无符号右移(>>>)

不保留符号位,从第32位开始向右移指定位数

正数与有符号右移相同,但是负数会出现改变符号位的情况

综合应用

rgb与16进制互相转换

16进制转rgb

  1. rgb的通常表示为rgb(r,g,b)

  2. rgb的值得范围是0-255(这是十进制),那么转成二进制就是8位

  3. 那么我们要取r的值只需要向右偏移16位(去掉g和b的值)

  4. 取g的值先向右偏移8位(去掉b的值)然后匹配后8位(oxff的值是11111111)

  5. 取b的值就是直接匹配后8位

    function hexToRGB(hex){ var hex = hex.replace("#","0x"), r = hex >> 16, g = hex >> 8 & 0xff, b = hex & 0xff; return rgb(${r},${g},${b}); }

rgb转16进制

就是跟上面差不多,反向理解下就行

function RGBToHex(rgb){
    var rgbArr = rgb.split(/[^\d]+/),
        color = rgbArr[1]<<16 | rgbArr[2]<<8 | rgbArr[3];
    return "#"+color.toString(16);
}

参考:《JavaScript高级程序设计》

感谢阅读

image.png