js 二进制位运算实践

646 阅读1分钟

概述

作用速度快,都作用于32位整数,二进制位运算符用于直接对二进制位进行计算

二进制运算符有那些

运算符表达式备注
按位与a & b若两个二进制位都为1,则结果为1,否则为0
按位或a | b若两个二进制位都为0,则结果为0,否则为1
按位异或a ^ b若两个二进制位不相同,则结果为1,否则为0
按位非~ a反转操作数的二制位,即0变成1,1变成0。
左移a << b将 a 的二进制形式向左移 b (< 32) 位,右边用0填充。
有符号右移a >> b将 a 的二进制表示向右移 b (< 32) 位,丢弃被移出的位。
无符号右移a >>> b将 a 的二进制表示向右移 b (< 32) 位,丢弃被移出的位,并使用 0 在左侧填充。

常用应用

判断数字奇偶性

4 & 1 === 0
5 & 1 === 1

权限控制

通过 <<,&,| 进行权限控制

ready = 1 // 读的权限(1write = 1 << 2 // 写的权限(10execute = 1 << 3 // 执行权限(100)
// 假如有读和写的权限
permissions = ready | write // (11)

if (ready & permissons){ // 1 & 11 => 1 
}
if (write & permissons) { // 10 & 11 => 4
}
if (execute & permissons) {  100 & 11 => 0
}
// vue中的PatchFlags
export const enum PatchFlags {
  TEXT = 1,
  CLASS = 1 << 1,
  STYLE = 1 << 2,
  PROPS = 1 << 3,
  FULL_PROPS = 1 << 4,
  HYDRATE_EVENTS = 1 << 5,
  STABLE_FRAGMENT = 1 << 6,
  KEYED_FRAGMENT = 1 << 7,
  UNKEYED_FRAGMENT = 1 << 8,
  NEED_PATCH = 1 << 9,
  DYNAMIC_SLOTS = 1 << 10,
  DEV_ROOT_FRAGMENT = 1 << 11,
  HOISTED = -1,
  BAIL = -2
}
const flag = TEXT | CLASS
if (flag & TEXT) { ... }

数字取整

使用~, >>, <<, >>>, |来取整,因为都是作用在32位的整数上,小数会直接忽略

console.log(~~ 1.22) // 1
console.log(1.22 >> 0) // 1 
console.log(1.22 << 0) // 1
console.log(1.82 | 0) // 1 
// >>>不可对负数取整 
console.log(3.45 >>> 0) // 3

将 -1 转为 0

// indexOf,lastIndexOf
~'abc'.indexOf('n') // 0 ~符可以 表示 -(x + 1)=> -(-1+1) => 0

位运算不是为了装逼

上面概述里面就讲了,位运算是作用二进制,速度快,下面实测

console.time('|0向下取整')
for(var i = 0; i < 1000000; i ++){
    i/7 | 0
}
console.timeEnd('|0向下取整')

console.time('Math.floor')
for(var i = 0; i < 1000000; i ++){
    Math.floor(i / 3)
}
console.timeEnd('Math.floor')

WechatIMG6.png

var b = 1 << 3
var c = a | b
console.time('位运算权限')
for(var i = 0; i < 1000000; i ++){
    if(a & c){}
}
console.timeEnd('位运算权限')

console.time('indexOf')
for(var i = 0; i < 1000000; i ++){
    if([4, 8].indexOf(4) > -1) {}
}
console.timeEnd('indexOf')

image.png

位运算在性能上有一定的效果,装逼不存在的,当然这点性能,在日常开发基本无用,对于算法追求极速,还是不错的;不过通过位运算达到的极简优雅写法还是很吸引人的