• JavaScript的位操作符你知道吗?



    前言

    什么是JavaScript位操作符?🤔

    其实 JavaScript 位操作符是数值的底层操作,用来操作内存中表示数据的比特位,我们都知道 JavaScript 中的所有数值都是以 64 位格式存储的数据,我们要说的位操作符不会直接运用到64位表示,而是先将值转换为 32 位整数进行位操作,再转换为 64 位


    铺垫

    有符号整数使用 32 位的前 31 位表示整数值,第 32 位(符号位)表示数值的符号(0表示正 ,1表示负)

    如果是一个正值,那么会以真正的二进制格式存储,也就是说 31 位中的每一位都代表这 2 的幂,空位补零(忽略不计),比如 十进制数 18 的二进制格式为:00000000000000000000000000010010,这还能看?😅,我们简写一下:10010,我们使用这五个有效位就可以了

    请添加图片描述

    如果十进制数为负数的话,会以一种 二补数 的二进制编码存储:

    • 确定绝对值的二进制表示
    • 找到数值的一补数
    • 给结果加一

    我们来演示一下:

    # 确定绝对值的二进制表示
    00000000000000000000000000010010
    
    # 找到数值的一补数
    11111111111111111111111111101101
    
    #  给结果加一
    11111111111111111111111111101110
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    所以 -18 的二进制数是 101110,把负值输出为一个二进制字符串的时候,我们会得到一个前面加了减号的绝对值,不过转换过程会求得二补数,只是以一种更加符合逻辑的形式表现出来,我们上代码验证一下:

    请添加图片描述

    如果是非数值的话,JavaScript 会自动调用 Number() 函数进行处理,处理之后进行位操作

    BUG:在对 JavaScript 中的数值使用位操作符的时候,在后台 64 位数值会转换为 32 位数值,然后执行位操作,最后再把 32 位数值转换为 64 位数值存储起来,这个转换的过程也导致了一个BUG,不过也不能叫BUG,可以说是一个副作用吧,当我们对 NaNInfinity 执行位操作的时候会被当成 0 处理


    位操作符

    按位非(~)

    按位非操作符的功能是返回数值的一补数

    let num = 18
    let num2 = ~num
    
    console.log(num2)
    // -19
    
    • 1
    • 2
    • 3
    • 4
    • 5

    这不就是取反减一嘛🤔

    let num = 18
    let num2 = ~num
    
    console.log(num2)
    // -19
    
    • 1
    • 2
    • 3
    • 4
    • 5
    let num = 18
    let num2 = -num - 1
    
    console.log(num2)
    
    • 1
    • 2
    • 3
    • 4

    不过这可没有 ~ 位操作符在底层执行的快


    按位与(&)

    按位与可操作俩个数值,基于真值表进行比较并操作:

    请添加图片描述

    不难看出按位与操作符俩个位都为 1 返回 1,有一个位为 0 ,则返回 0

    let num = 25 & 3
    console.log(num)
    // 1
    
    • 1
    • 2
    • 3
    25  = 00000000000000000000000000011001
    
    3   = 00000000000000000000000000000011
    
    结果:00000000000000000000000000000001
    
    • 1
    • 2
    • 3
    • 4
    • 5

    按位或( | )

    依旧是比较真值表:有一位是 1 返回 1,俩位都是 0 ,返回 0

    let num = 25 | 3
    console.log(num)
    // 27
    
    • 1
    • 2
    • 3
    25  = 00000000000000000000000000011001
    
    3   = 00000000000000000000000000000011
    
    结果:00000000000000000000000000011011
    
    • 1
    • 2
    • 3
    • 4
    • 5

    按位异或(^)

    还是我们的真值表:只有一位为 1 ,返回 1,俩位都是 1 或者 0 ,返回 0

    let num = 25 ^ 3
    console.log(num)
    // 26
    
    • 1
    • 2
    • 3
    25  = 00000000000000000000000000011001
    
    3   = 00000000000000000000000000000011
    
    结果:00000000000000000000000000011010
    
    • 1
    • 2
    • 3
    • 4
    • 5

    左移(<<<)

    按照指定位数将数值的所有位向左移

    let num = 2
    
    let new_num = num << 5
    console.log(new_num)
    // 64
    
    • 1
    • 2
    • 3
    • 4
    • 5
    #()中的为符号位
    
    2  = (0)0000000000000000000000000000010
    
    # 向左移5位 -- 空位补零
    
    (0)00000000000000000000000010[00000] = 64
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    // 左移会保留它所操作数值的符号
    let num = -2
    
    let new_num = num << 5
    console.log(new_num)
    // -64
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    有符号右移(>>)

    这没有什么可说的,值得注意的一点就是右移后空位出现在左侧的符号位之后,而 JavaScript 会使用符号位的值来填充这些空位,得到完整的数值

    无符号右移(>>>)

    如果数值是一个正数的话,那么它和>>是一样的,一但是负数,>>> 则会将负数的二进制表示当成正数的二进制来进行处理,但负数是数值绝对值的二补数,所以右移之后结果会非常之大:

    let num = -2
    
    let new_num = num >>> 5
    console.log(new_num)
    // 134217727
    
    • 1
    • 2
    • 3
    • 4
    • 5
  • 相关阅读:
    UE4创建一个左右摇摆的“喷泉”
    uniapp无感刷新token实现过程
    安全文件传输如何进行管控,从而促进业务的有序发展?
    十年架构师带来的Spring源码解析,极度深寒,程序员修炼内功必备
    Java内存模型与线程(2)
    Bayer 模式图像(bggr ,grbg, gbrg)转rgb888
    博物馆文物的保护环境对温湿度的要求
    VUE 脚手架框架 编写一个简洁的登录界面
    (219)Verilog HDL:实现简单 FSM2(同步复位)
    PG学习笔记(PostgreSQL)
  • 原文地址:https://blog.csdn.net/weixin_63836026/article/details/126267391