1.位运算符的定义
位运算是在数字底层(即表示数字的 32 个数位)进行运算的。由于位运算是低级的运算操作,所以速度往往也是最快的(相对其它运算如加减乘除来说),并且借助位运算有时我们还能实现更简单的程序逻辑,缺点是很不直观,许多场合不能够使用。
2.关于二进制
ECMAScript 整数有两种类型,即有符号整数(允许用正数和负数)和无符号整数(只允许用正数)。有符号整数使用 32 位的前 31 位表示整数值。第 32 位表示数值的符号,如 0 表示正,1 表示负。这
一位称为符号位(sign bit),它的值决定了数值其余部分的格式。正值以真正的二进制格式存储,即 31位中的每一位都代表 2 的幂。第一位(称为第 0 位)表示 20(2的0次方),第二位表示 21,依此类推。如果一个位是空的,则以0填充,相当于忽略不计,比如,数值18的二进制格式为00000000000000000000000000010010,或更精简的 10010。后者是用到的 5 个有效位,决定了实际的值,如下图
3.二进制和十进制
3.1js代码进行转化
// 十进制 => 二进制
let num = 10;
console.log(num.toString(2));
// 二进制 => 十进制
let num1 = 1001;
console.log(parseInt(num1, 2));
3.2手动转化
// 二进制 => 十进制
// 十进制 => 二进制,使用短除法
4.概况
5.详解及应用
5.1按位或 |
|与||操作符的道理也是一样的,只要两个数中有一个数为1,结果就为1,其他则为0
5.1.1 或|的应用场景
用或 | 操作,在实际应用中,我们可以实现向下取整,即int = num | 0,因为位运算是对整数操作的,当遇到浮点型的数值时,会先将浮点型的数据转成整型,然后再进行或运算,因为|只有其中一个数为1结果就是1,而0的二进制也是0,所以可实现向下取整
3.7 | 0 //3
1.1 | 0 //1
5.2按位与 &
&运算符表示只有两个数的值为1时,才返回1
5.2.1 &的应用场景
我们管理系统做表单checkbox多选是,加入我们有a、b、c、d四个chebox的选项,1,2,4,8分别代表checkbox的value值,当我们全选a + b + c + d的时候,可以将1 | 2 | 4 | 8 = 15传给java后台,如果只选择a + c的时候,则传递给java后台的值为1 | 4 = 5。
那么我们做编辑功能的时候,如何判断checkbox是否被选中?很简单,用&符号就可以,比如用户选择了a+c,后台给我们返回5,c的值为1,那么 4 & 5 = 4, b的选项我们是没有选择的,则 2 & 5 = 5,也就是说,选中的通过&的运算值为>0的值,没有选中的将会为0。
1 | 2 | 4 | 8 = 15
1 | 4 = 5
4 & 5 = 4
2 & 5 = 0
这种实现方式在做系统权限特别好友,不过要特别注意的是,checkbox的值必须为2的幂次方,并且最大值为2的31次方。
5.3 按位异或 ^
两个操作数相应的比特位有且只有一个1时,结果为1,否则为0
5.3.1应用场景
(1)假如我们通过某个条件来切换一个值为0或者1
//普通的写法
function update(toggle) {
var num = toggle ? 1 : 0;
console.log(num)
}
update(true);
// 通过异或我们可以这么写
num = num ^ 1; //num为true的返回 0, 为 false返回1
(2)可以在不使用第三变量的值得情况下交换两个变量的值
let a = 5,
b = 6;
a = a ^ b;
b = a ^ b;
a = a ^ b;
(3)可以实现简单的加密
const key = 313;
function encryption(str) {
let s = '';
str.split('').map(item => {
s += handle(item);
})
return s;
}
function decryption(str) {
let s = '';
str.split('').map(item => {
s += handle(item);
})
return s;
}
function handle(str) {
if (/\d/.test(str)) {
return str ^ key;
} else {
let code = str.charCodeAt();
let newCode = code ^ key;
return String.fromCharCode(newCode);
}
}
let init = 'hello world 位运算';
let result = encryption(init); // őŜŕŕŖęŎŖŋŕŝę乴軩窮
let decodeResult = decryption(result); // hello world 位运算
5.4 按位非~
按位非就是求二进制的反码的操作。对数值进行非运算主要有一下步骤:
(1)求数值二进制,如var num = 1; // 二进制 00000000000000000000000000000001
(2)取该值得反码为: num2 = 11111111111111111111111111111110
(3)第32位符号位的值不变,num2其他为位在取反码后位 num3 = 10000000000000000000000000000001
(4)然后加1为10000000000000000000000000000010,即-2,也就是1的按非~运算结果为-2
5.4.1应用场景
// 常用判断
if (arr.indexOf(item) > -1) {
// code
}
// 按位非 ~-1 = - (-1 + 1)
if (~arr.indexOf(item)) {
// code
}
5.5 左移 <<
该操作符会将第一个操作数向左移动指定的位数。向左被移出的位被丢弃,右侧用 0 补充。
例如 3 << 2 的运算图示如下:
3 = 0000 0000 0000 0000 0000 0000 0000 0011
12 = 0000 0000 0000 0000 0000 0000 0000 1100
5.6 有符号右移 >>
该操作符会将第一个操作数向右移动指定的位数。向右被移出的位被丢弃,拷贝最左侧的位以填充左侧。由于新的最左侧的位总是和以前相同,符号位没有被改变。所以被称作“符号传播”。
例如3>>2
3 = 0000 0000 0000 0000 0000 0000 0000 0011
0 = 0000 0000 0000 0000 0000 0000 0000 0000
5.7 无符号右移>>>
该操作符会将第一个操作数向右移动指定的位数。向右被移出的位被丢弃,左侧用0填充。因为符号位变成了 0,所以结果总是非负的。(译注:即便右移 0 个比特,结果也是非负的。)
var num = -64; // 11111111111111111111111111000000(负数采用的是补码表示)
num = num >>> 5; // 134217726
a.64的补码是1000000
b.取它的反码为11111111111111111111111110111111
c.加1得她的补码为11111111111111111111111111000000
d.无符号右移5位位00000111111111111111111111111110
//求负整数的补码,将其原码除符号位外的所有位取反(0变1,1变0,符号位为1不变)后加1
6.总结
位运算是在数字底层进行操作的,运算速度快,书写简洁,但是很多场景没法使用,也不够直观。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。