JS中的位运算 - 废材壶 BLOG
    JS中的位运算
    在计算机中,所有的数据和指令在底层都是以二进制数的形式存储和处理的。二进制数使用两个字符(0和1)来表示数字,每一位代表一个不同的幂次
    29 June, 2024

    二进制数简介

    • 探索之前我们先复习一遍二进制中的基础知识概要

    在计算机中,所有的数据和指令在底层都是以二进制数的形式存储和处理的。二进制数使用两个字符(0和1)来表示数字,每一位代表一个不同的幂次。对于二进制数 1010 来说:

    简介
    简介

    加起来: 232^3 + 0 + 212^1 + 0 = 10

    在JS中,二进制数可以通过前缀 0b0B 来表示。例如:

    let binaryNum = 0b1010 // 二进制数表示法
    

    将二进制数转位十进制

    • 使用 Number
    • 使用 parseInt
    Number(0b1010) // 10
    parseInt('1010', 2) // 10
    

    将十进位数转位二进制数

    • 使用 toString
    Number(10).toString(2) // '1010'
    

    除了创建和转换二进制数外,JS还提供一些操作二进制数的方法。

    位运算

    • 位运算符是操作二进制数的方法

    按位运算符会将其操作数转换为 32 位有符号整数,再执行运算

    按位与 (&)

    a & b 规则:两个1返回1,不同为0

    let a = 0b1101 // 13
    let b = 0b0011 // 3
    let c = a & b // 1
    

    按位与
    按位与

    按位或(|)

    a | b 规则:对应位,存在一个1就是1,否则就是0

    let a = 0b1101 // 13
    let b = 0b0011 // 3
    let c = a | b // 15
    

    按位或
    按位或

    按位异或(^)

    a ^ b 规则是:两个对应位不同返回1,否则是0

    let a = 0b1101 // 13
    let b = 0b0011 // 3
    let c = a ^ b // 14
    

    按位异或
    按位异或

    按位非(~)

    ~a 规则是:按位取反

    使用补码表示法

    1. 在JS中会将操作数转为32位整数,然后再对每一位进行取反操作。

      如上我们用的例子 let a = 0b1101 转为32位整数为 0000 0000 0000 0000 0000 0000 0000 1101

    2. 取反后为负数 1111 1111 1111 1111 1111 1111 1111 0010

    3. 要把负数补码转为负数原码。负数的补码是符号位不变,减1

    4. 补码表示为: 1111 1111 1111 1111 1111 1111 1111 0001

    5. 取反为:1000 0000 0000 0000 0000 0000 0000 1110

    故补码表示为其最后的结果结果

    let a = 0b1101 // 13
    ~a // -0b1110 -> -14
    

    左移(<<)

    a << b 规则为:将 a 的位数往左移 b 位数,右边空缺则补0

    …0000 1101

    …0000 0011


    …0110 1000

    let a = 0b1101 // 13
    let b = 0b0011 // 3
    let c = a << b // 104
    

    左移赋值 (<<=)

    左移简写,上面的例子使用 左移赋值简写的话是 a <<= 3

    右移(>>)

    a >> b 规则为:将 a 的位数往右移 b 位数,右边移出抛弃,左边空缺则补符号位

    …0000 1101

    …0000 0011


    …0000 0001

    let a = 0b1101 //13
    let b = 0b0011 // 3
    let c = a >> b // 1
    

    无符号右移 (<<<)

    a >>> b 规则是:区别于右移是,左边空缺的填充0

    应用场景

    使用位运算符的应用场景

    标识符

    例如 rollup 源码中,使用了左移运算符,创建唯一的按位操作友好的标识符。

    export const enum Flag {
    	included = 1 << 0,
    	deoptimized = 1 << 1,
    	tdzAccessDefined = 1 << 2,
    	tdzAccess = 1 << 3
    	...
    }
    
    export function isFlagSet(flags: number, flag: Flag): boolean {
    	return (flags & flag) !== 0;
    }
    
    export function setFlag(flags: number, flag: Flag, value: boolean): number {
    	return (flags & ~flag) | (-value & flag);
    }
    

    权限管理

    const READ = 0b001;
    const WRITE = 0b010;
    const EXECUTE = 0b100;
    
    let permissions = 0;
    
    // 设置权限
    permissions |= READ | WRITE;
    
    // 检查权限
    let canRead = (permissions & READ) !== 0;
    let canWrite = (permissions & WRITE) !== 0;
    let canExecute = (permissions & EXECUTE) !== 0;
    
    console.log({ canRead, canWrite, canExecute }); // { canRead: true, canWrite: true, canExecute: false }
    
    // 取消权限
    permissions &= ~WRITE;
    canWrite = (permissions & WRITE) !== 0;
    console.log({ canWrite }); // { canWrite: false }
    
    Jimhug

    基础不牢,地动山摇

    Share with the post url and description