通过学习 React 源码,使用位运算来实现权限管理,实在是太简单了 😉😉😉
在 React 中,lane 是用来标识更新优先级的位掩码,它可以在频繁运算的时候占用内存少,计算速度快。每个 lane 代表一种优先级级别,React 可以同时处理多个 lane,通过这种方式来管理不同优先级的任务。
位运算的基本操作
以下是位运算的一些基本操作的详细讲解,包括与(AND)、或(OR)、异或(XOR)、取反(NOT)、左移(Left Shift)、右移(Right Shift)操作:
-
与(AND): 对应位都为 1 时,结果为 1,否则为 0。
-
或(OR): 对应位只要有一个为 1,结果就为 1。
-
异或(XOR): 对应位不同,结果为 1,相同为 0。
-
取反(NOT): 将每一位取反,0 变 1,1 变 0。
-
左移(Left Shift): 将二进制数的位向左移动,右边补 0。
-
右移(Right Shift): 将二进制数的位向右移动,左边补符号位(正数补 0,负数补 1)。
如下是使用位运算的一些基本操作,它包括与(AND)、或(OR)、异或(XOR)、取反(NOT)、左移(Left Shift)、右移(Right Shift)操作:
// 与(AND)操作
const a = 5; // 二进制: 0101
const b = 3; // 二进制: 0011
const andResult = a & b;
console.log(`${a} & ${b} = ${andResult}`); // 输出: 1 (二进制: 0001)
// 或(OR)操作
const orResult = a | b;
console.log(`${a} | ${b} = ${orResult}`); // 输出: 7 (二进制: 0111)
// 异或(XOR)操作
const xorResult = a ^ b;
console.log(`${a} ^ ${b} = ${xorResult}`); // 输出: 6 (二进制: 0110)
// 取反(NOT)操作
const notResult = ~a;
console.log(`~${a} = ${notResult}`); // 输出: -6 (二进制: 1010)
// 左移(Left Shift)操作
const leftShiftResult = a << 1;
console.log(`${a} << 1 = ${leftShiftResult}`); // 输出: 10 (二进制: 1010)
// 右移(Right Shift)操作
const rightShiftResult = a >> 1;
console.log(`${a} >> 1 = ${rightShiftResult}`); // 输出: 2 (二进制: 0010)
最终输出结果如下图所示:
在 React 中,它的 lane 模型里面的一些基本运算都封装成了一个函数,如下代码所示:
// 获取指定 Lanes 中的任意一个 Lane 的索引
function pickArbitraryLaneIndex(lanes: Lanes) {
return 31 - clz32(lanes);
}
// 将单个 Lane 转换为其索引
function laneToIndex(lane: Lane) {
return pickArbitraryLaneIndex(lane);
}
// 判断两个 lanes 集合之间是否有交集
export function includesSomeLane(a: Lanes | Lane, b: Lanes | Lane) {
return (a & b) !== NoLanes;
}
// 判断两个 lanes 集合是否是父子集的关系
export function isSubsetOfLanes(set: Lanes, subset: Lanes | Lane) {
return (set & subset) === subset;
}
// 合并两个 lanes 集合
export function mergeLanes(a: Lanes | Lane, b: Lanes | Lane): Lanes {
return a | b;
}
// 从一个 lanes 集合中把某个 lane 或者 lanes 集合给移除掉,相当于求一个集合的补集
export function removeLanes(set: Lanes, subset: Lanes | Lane): Lanes {
return set & ~subset;
}
// 求两个 lanes 集合的交集
export function intersectLanes(a: Lanes | Lane, b: Lanes | Lane): Lanes {
return a & b;
}
这些函数主要用于管理和操作 Lanes 集合,通过位运算来实现高效的集合操作。位运算能够非常高效地处理集合的交集、并集、补集等操作,常用于需要快速处理和管理状态集合的场景,如调度任务。
如何基于位运算来实现权限操作
使用位运算来实现权限管理是一种高效且常见的方法。每个权限都可以表示为一个位(bit),通过位运算可以轻松地检查、添加、删除和组合权限。
-
定义权限:每个权限都对应一个位。
-
分配权限:使用位运算将多个权限组合在一起。
-
检查权限:使用位运算检查是否具备某个权限。
-
添加权限:使用位运算添加权限。
-
移除权限:使用位运算移除权限。
假设我们有如下的权限:
-
读取 (Read) 权限:位移表示:1 << 0,二进制表示:0b0001
-
写入 (Write) 权限:位移表示:1 << 1,二进制表示:0b0010
-
执行 (Execute) 权限:位移表示:1 << 2,二进制表示:0b0100
-
删除 (Delete) 权限:位移表示:1 << 3,二进制表示:0b1000
-
管理 (Admin) 权限:位移表示:1 << 4,二进制表示:0b10000
-
创建 (Create) 权限:位移表示:1 << 5,二进制表示:0b100000
-
查看 (View) 权限:位移表示:1 << 6,二进制表示:0b1000000
首先我们先定义这些权限
// 权限定义
const READ = 1 << 0; // 0b0001
const WRITE = 1 << 1; // 0b0010
const EXECUTE = 1 << 2; // 0b0100
const DELETE = 1 << 3; // 0b1000
const ADMIN = 1 << 4; // 0b10000
const CREATE = 1 << 5; // 0b100000
const VIEW = 1 << 6; // 0b1000000
// 将数字转换为二进制字符串并打印,添加 0b 前缀
const toBinaryString = (num, length = 8) =>
"0b" + num.toString(2).padStart(length, "0");
console.log("二进制表示:");
console.log("读取 (READ):", toBinaryString(READ)); // 0b00000001
console.log("写入 (WRITE):", toBinaryString(WRITE)); // 0b00000010
console.log("执行 (EXECUTE):", toBinaryString(EXECUTE)); // 0b00000100
console.log("删除 (DELETE):", toBinaryString(DELETE)); // 0b00001000
console.log("管理 (ADMIN):", toBinaryString(ADMIN)); // 0b00010000
console.log("创建 (CREATE):", toBinaryString(CREATE)); // 0b00100000
console.log("查看 (VIEW):", toBinaryString(VIEW)); // 0b01000000
最终输出结果如下图所示:
通过一些基本操作,我们可以高效地管理和操作用户的权限,如下代码所示:
// 组合权限
let userPermissions = READ | WRITE | VIEW; // 组合权限,等于 0b01000011
// 检查权限函数
const hasPermission = (permissions, permission) =>
(permissions & permission) !== 0;
console.log("\n初始权限:");
console.log("用户权限 (userPermissions):", toBinaryString(userPermissions)); // 0b01000011
console.log("读取 (Read):", hasPermission(userPermissions, READ)); // true
console.log("写入 (Write):", hasPermission(userPermissions, WRITE)); // true
console.log("执行 (Execute):", hasPermission(userPermissions, EXECUTE)); // false
console.log("删除 (Delete):", hasPermission(userPermissions, DELETE)); // false
console.log("管理 (Admin):", hasPermission(userPermissions, ADMIN)); // false
console.log("创建 (Create):", hasPermission(userPermissions, CREATE)); // false
console.log("查看 (View):", hasPermission(userPermissions, VIEW)); // true
// 添加权限函数
const addPermission = (permissions, permission) => permissions | permission;
// 移除权限函数
const removePermission = (permissions, permission) => permissions & ~permission;
// 添加执行权限
userPermissions = addPermission(userPermissions, EXECUTE);
console.log("\n添加执行权限后:");
console.log("用户权限 (userPermissions):", toBinaryString(userPermissions)); // 0b01000111
console.log("读取 (Read):", hasPermission(userPermissions, READ)); // true
console.log("写入 (Write):", hasPermission(userPermissions, WRITE)); // true
console.log("执行 (Execute):", hasPermission(userPermissions, EXECUTE)); // true
console.log("删除 (Delete):", hasPermission(userPermissions, DELETE)); // false
console.log("管理 (Admin):", hasPermission(userPermissions, ADMIN)); // false
console.log("创建 (Create):", hasPermission(userPermissions, CREATE)); // false
console.log("查看 (View):", hasPermission(userPermissions, VIEW)); // true
// 移除写入权限
userPermissions = removePermission(userPermissions, WRITE);
console.log("\n移除写入权限后:");
console.log("用户权限 (userPermissions):", toBinaryString(userPermissions)); // 0b01000101
console.log("读取 (Read):", hasPermission(userPermissions, READ)); // true
console.log("写入 (Write):", hasPermission(userPermissions, WRITE)); // false
console.log("执行 (Execute):", hasPermission(userPermissions, EXECUTE)); // true
console.log("删除 (Delete):", hasPermission(userPermissions, DELETE)); // false
console.log("管理 (Admin):", hasPermission(userPermissions, ADMIN)); // false
console.log("创建 (Create):", hasPermission(userPermissions, CREATE)); // false
console.log("查看 (View):", hasPermission(userPermissions, VIEW)); // true
最终输出结果如下图所示:
通过这种方式我们就可以便捷地管理我们项目中的权限了。
总结
位运算操作快速且占用内存少,容易理解和使用,可以灵活地组合、添加和移除权限,并且可以轻松扩展权限种类。但是前提是你需要对二进制这些内容有一定的理解。
转载自:https://juejin.cn/post/7394786709647278080