React 位运算

作者: shaokang 时间: July 9, 2024字数:3314

位运算

位运算就是基于整数的二进制表示进行的运算。由于计算机内部就是以二进制来存储数据,位运算是相当快的,但不直观且只支持整数运算。

合理的运用位运算更能显著提高代码在机器上的执行效率。

特性

位运算 用法 描述
与(&) a & b 两个对应位都为 1 时,结果为 1,否则为 0
或(\|) a \| b 两个对应位都为 0 时,结果为 0,否则为 1
异或(^) a ^ b 两个对应位相同时,结果为 0,否则为 1
非/取反(~) ~ a 反转操作数, 即 0 变成 1, 1 变成 0
左移(<<) a << b 将 a 的二进制形式向左移 b (< 32) 位,右边用 0 填充
右移(>>) a >>> b 将 a 的二进制形式向右移 b (< 32) 比特位,左侧补 0

JS 中位运算中的左右操作数都转换为有符号32位整型, 且返回结果也是有符号32位整型

  • 当操作数是浮点型时首先会被转换成整型(丢弃小数位),再进行位运算
  • 当操作数过大,超过了Int32范围,超过的部分会被截取

基本使用

基本使用

枚举属性:

通过位移的方式, 定义一些枚举常量

const A = 1 << 0; // 0b00000001
const B = 1 << 1; // 0b00000010
const C = 1 << 2; // 0b00000100

位掩码:

通过位移定义的一组枚举常量, 可以利用位掩码的特性, 快速操作这些枚举产量(增加, 删除, 比较).

  1. 属性增加|
    1. ABC = A | B | C
  2. 属性删除& ~
    1. AB = ABC & ~C
  3. 属性比较
    1. AB 当中包含 B: AB & B === B
    2. AB 当中不包含 C: AB & C === 0
    3. A 和 B 相等: A === B
const A = 1 << 0; // 0b00000001
const B = 1 << 1; // 0b00000010
const C = 1 << 2; // 0b00000100

// 增加属性
const ABC = A | B | C; // 0b00000111
// 删除属性
const AB = ABC & ~C; // 0b00000011

// 属性比较
// 1. AB当中包含B
console.log((AB & B) === B); // true
// 2. AB当中不包含C
console.log((AB & C) === 0); // true
// 3. A和B相等
console.log(A === B); // false

React 中的使用场景

优先级管理 lanes

lanes 是17.x版本中开始引入的重要概念,代替了16.x版本中的expirationTime,作为fiber对象的一个属性(位react-reconciler包),主要控制 fiber 树在构造过程中的优先级。

变量定义:

源码ReactFiberLane.js中的定义

export type Lanes = number;
export type Lane = number;

export const NoLanes: Lanes = /*                        */ 0b0000000000000000000000000000000;
export const NoLane: Lane = /*                          */ 0b0000000000000000000000000000000;

export const SyncLane: Lane = /*                        */ 0b0000000000000000000000000000001;
export const SyncBatchedLane: Lane = /*                 */ 0b0000000000000000000000000000010;

export const InputDiscreteHydrationLane: Lane = /*      */ 0b0000000000000000000000000000100;
const InputDiscreteLanes: Lanes = /*                    */ 0b0000000000000000000000000011000;

const InputContinuousHydrationLane: Lane = /*           */ 0b0000000000000000000000000100000;
const InputContinuousLanes: Lanes = /*                  */ 0b0000000000000000000000011000000;
// ...

一些方法定义:

  • getHighestPriorityLanes: 获取最高优先级
function getHighestPriorityLanes(lanes: Lanes | Lane): Lanes {
    // 判断 lanes中是否包含 SyncLane
    if ((SyncLane & lanes) !== NoLanes) {
        return_highestLanePriority = SyncLanePriority;
        return SyncLane;
    }
    // 判断 lanes中是否包含 SyncBatchedLane
    if ((SyncBatchedLane & lanes) !== NoLanes) {
        return_highestLanePriority = SyncBatchedLanePriority;
        return SyncBatchedLane;
    }
    // ...
    // ... 省略其他代码
    return lanes;
}
  • getHighestPriorityLane: 分离出最高优先级
function getHighestPriorityLane(lanes: Lanes) {
    return lanes & -lanes;
}
  • getLowestPriorityLane: 分离出最低优先级
function getLowestPriorityLane(lanes: Lanes): Lane {
    // This finds the most significant non-zero bit.
    const index = 31 - clz32(lanes);
    return index < 0 ? NoLanes : 1 << index;
}

总结

React 中有大量的位运算的应用,比如 ReactFiberLane.js 中的优先级管理,除此之外还有 ExecutionContexteffectTags 的使用。使用位运算不仅是提高运算速度,且位掩码能简洁和清晰的表示出二进制变量之间的关系。