You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
let a = 1, b = 2;
a ^= b; //假设两个变量a'和b'用于保存新的a和b的值 => a' = a ^ b
b ^= a; //此处a其实是a' => b' = b ^ a' === b ^ (a ^ b) === (b ^ b) ^ a === a
a ^= b; // 此时b其实已经为b' => a' = a' ^ b' === a ^ b ^ a = b
console.log(a, b) // 等价于输出 a' 和 b' => 2, 1
function abs (n) {
let a = n >> 31; // 通过移位获取符号位, 如果是正数 a为0,反之为-1
return a === 0 ? n : (~n + 1);
}
还用常见的:
~xxx.indexOf(x) // 利用的就是 ~(-1) === 0 如果不存在则返回空
5. 左移(<<)&右移(>>)
按位移动操作符有两个操作数:第一个是要被移动的数字,而第二个是要移动的长度。移动的方向根据操作符的不同而不同。平时用的最多的就是 n >> 1 === n / 2 并向下取整,还有 n << 1 === n*2。
可以结合按位或运算,给定一个数n,计算不超过n的2的最大倍数m,例如n=15,则m=8:
function largestPower(N) {
//将右边所有位都置为1.
N = N | (N>>1);
N = N | (N>>2);
N = N | (N>>4);
N = N | (N>>8);
N = N | (N>>16);
return (N+1)>>1;
}
概述
虽然在js的世界中,使用的数字类型都是十进制的,然而经常可见一些按位操作:
自己写码虽很少用按位操作符,但看到这些代码时,如果没有一些注释理解起来却是有些难度。
按位操作符(Bitwise operators) 将其操作数(operands)当作32位的比特序列(即二进制表示)进行操作,但其返回值依然是标准的JavaScript数值。
在js中可以使用toString将一个数值装换成二进制形式,当然也可以使用parseInt将一个二进制字符串解析成数值:
按位操作符类型
1. 按位与(&)
对每对比特位执行与(&)操作。只有 a 和 b 都是 1 时,a & b 才是 1:
利用这个特性,可以判断一个数是否是2的指数倍:
其原理是,假设一个数n=2^m,用二进制(31位表示)表示n时,其第31-m位总是为1,其余都是0,而n-1的二进制表示时,其31-m-1至31都是1,其余都是0,例如对于64:
同理也可以利用按位与(&)的特性来判断一个数是否是偶数/奇数:
2. 按位或(|)
对每一对比特位执行或(|)操作。如果 a 或 b 为 1,则 a | b 结果为 1:
因为位运算只对整数有效,遇到小数时,会将小数部分舍去,结合或运算的特性,可以很容易实现类似Math.floor向下取整的功能:
3. 按位异或(^)
对每一对比特位执行异或(^)操作。当 a 和 b 不相同时,a ^ b 的结果为 1:
当一个数n, n ^ n结果总是为0,而任意一个数与0进行异或操作,其结果都不会变。所以利用异或操作,可以很容易类似「缺失的数字」,一个只包含数字的数组中,数字本应都是成对出现,由于意外某个数字丢失,需要找个这个丢失的数字,例如[1, 2, 3, 1, 3]的缺失数字为2:
使用异或这个特性也可以交换两个变量的值:
平时求两个数值的和,可以简单的使用
a + b
,然而某一天编译器对+
解析出现了异常(虽然不现实,假设一下...),不允许用+
求数值和之后该怎么办?答案就是结合异或操作(^)好按位与(&)操作:
然后实例论证一下上述过程,假如这两个数a、b分别为7、3,其对应的二进制形式分别为
0111
和0011
,正常二进制数加法思路和十进制数加法都一样为:1+1
结果为2 ,需要往前一位进1,然后把结果置为0;1 + 1 + 1(进位)
结果为3, 往前近一位,结果至为1;1010
进行按位操作时异或操作在不考虑进位数前提下,只关注相加之后各位的结果值(1+1 => 0, 1 + 0 => 1),通过与操作统一处理进位数 ((1 & 1) * 2 => 1 * 2 => 10(二进制,相当于进了一位))
4. 按位非(~)
对每一个比特位执行非(~)操作。~a 结果为 a 的反转,对任一数值 x 进行按位非操作的结果为 -(x + 1)。例如,~5 结果为 -6。
由于计算机都是以
补码
, 具体可参考原码, 反码, 补码 详解形式存储数字的,故:利用其反转的特性,可以很容易实现类似Math.abs的功能:
还用常见的:
5. 左移(<<)&右移(>>)
按位移动操作符有两个操作数:第一个是要被移动的数字,而第二个是要移动的长度。移动的方向根据操作符的不同而不同。平时用的最多的就是 n >> 1 === n / 2 并向下取整,还有 n << 1 === n*2。
可以结合按位或运算,给定一个数n,计算不超过n的2的最大倍数m,例如n=15,则m=8:
总结
按位操作虽说不易,但在某些计算上,使用得当的情况下可以简化代码,效率或许也会有所提升哦,尤其是在需要使用标志位时,像封装可以打印不同等级(All, Debug, Waring)等提示信息的log.js。
参考
The text was updated successfully, but these errors were encountered: