稀土掘金技术社区 04月09日 18:06
用二进制思维重构前端权限系统
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

文章探讨了在权限管理中引入位运算的思想,包括权限的二进制表示、位运算符号、框架源码中的应用、算法中的应用以及实战构建位运算权限系统,还分析了其优缺点和后续思考。

💡传统权限系统的问题及位运算的引入

📌权限的二进制表示与位运算符号

🎨框架源码中位运算的应用实例

🧮位运算在算法中的应用

🛠️从零构建位运算权限系统及优缺点

原创 糟糕好吃 2025-03-14 08:30 北京

点击关注公众号,“技术干货”及时达!

点击关注公众号,“技术干货” 及时达!

一、一个真实开发场景引发的思考

某天,我在权限管理组件中写下了第5个isAdmin && canEdit || hasPermission('delete'),突然意识到——这种用布尔值堆砌的权限系统正在让我的代码变得臃肿。看似清晰的逻辑,实则暗藏着复杂的逻辑链条,这让我很容易忽视潜在的错误和维护的困难。特别是当权限的组合和复杂度不断增加时,传统的布尔值判断往往无法满足日益复杂的需求,代码也变得越来越难以理解和扩展。

此时,恍若灵光一现,我想起了React团队在管理Fiber节点时,如何利用二进制位运算来高效地管理节点的状态。React用0b1011这样的二进制数,表示节点的32种状态,极大提高了性能的同时,也简化了复杂状态的管理。这种做法,不仅保证了系统的高效运行,还让原本散乱的状态信息在二进制位中得以精确而清晰的表达。

同样,Vue3的虚拟DOM也通过位运算实现了快速判断节点类型和状态,避免了传统的遍历和比对,进一步提升了渲染效率。Vue3将不同的操作类型、生命周期状态、节点信息等通过位运算压缩在整数值中,这种方法不仅提高了性能,还降低了出错的可能性。

在这个对比中,我不禁思考:如果在权限管理中也能引入位运算的思想,是否能让复杂的权限控制更简洁、清晰和高效?比如,使用一个整数代表不同权限的组合,通过位运算来判断权限是否符合,既能避免多重嵌套判断,也能在权限的扩展上获得更大的灵活性。

二、从二进制到位运算

2.1 权限的二进制表示

在计算机中,二进制是最基本的数据表示方式。每一位二进制位(bit)都可以表示一个状态,0表示“无”,1表示“有”。在权限管理中,我们可以利用这一特性,将不同的权限映射到二进制的不同位上。

例如,假设我们有三种权限:读(Read)、写(Write)和执行(Execute)。我们可以将它们分别映射到二进制的不同位:

通过这种映射,我们可以使用一个整数来表示用户的所有权限。例如,权限值为7(二进制:111),表示用户同时拥有读、写和执行权限。

2.2 位运算符号

「1. 位运算符」

三、框架源码中的位运算艺术

3.1 React Fiber 状态压缩术

在React的reconciliation算法中,单个Fiber节点需要同时记录多种状态:

// react/packages/react-reconciler/src/ReactFiberFlags.js
export const Placement = 0b0000000000001;
export const Update = 0b0000000000010;
export const ChildDeletion = 0b0000000000100;
// 状态组合
let flags = Placement | Update; // 0b0000000000011
// 超高效状态检测
if (flags & Update) {
    // 执行副作用更新...
}

设计哲学:用1个32位整数替代32个布尔变量,内存占用减少96%,状态检测速度提升10倍。

3.2 Vue3 虚拟DOM类型快查

Vue3通过shapeFlag实现虚拟节点类型的闪电判断:

// vue-next/packages/shared/src/shapeFlags.ts
export const enum ShapeFlags {
    ELEMENT = 1,
    COMPONENT = 1 << 1,
    TEXT_CHILDREN = 1 << 2,
    ARRAY_CHILDREN = 1 << 3
}
// 动态组合类型
const vnodeFlag = ShapeFlags.ELEMENT | ShapeFlags.ARRAY_CHILDREN;
// 比switch快10倍的类型判断
if (vnodeFlag & ShapeFlags.COMPONENT) {
    // 处理组件逻辑...
}

性能对比:传统字符串类型判断需要遍历原型链,位运算直接访问寄存器,速度提升20倍。

四、位运算在算法中的应用

4.1 leetcode231 2的幂

/**
 * 给你一个整数 n,请你判断该整数是否是 2 的幂次方。如果是,返回 true ;否则,返回 false 。
 * 如果存在一个整数 x 使得 n == 2x ,则认为 n 是 2 的幂次方。
 * 
 * 示例 1:
 * 输入:n = 1
 * 输出:true
 * 
 * 示例 2:
 * 输入:n = 16
 * 输出:true
 * 
 * 示例 3:
 * 输入:n = 3
 * 输出:false
 */

function isPowerOfTwo(n{
    if (n <= 0return false;
    while (n > 1) {
        if (n % 2 !== 0return false;
        n = Math.floor(n / 2); // 使用 Math.floor 保证是整数除法
    }
    return true;
}
function isPowerOfTwo(n{
    return n > 0 && (n & (n - 1)) === 0;
}

解释:

4.2 leetcode 136 只出现一次的数字

/**
 * 给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
 * 
 * 示例 1:
 * 输入: [2,2,1]
 * 输出: 1
 * 
 * 示例 2:
 * 输入: [4,1,2,1,2]
 * 输出: 4
 * 
 */

var singleNumber = function(nums{
    let hashTable = {};
    for(let i = 0; i < nums.length; i++) {
        if(hashTable[nums[i]] == undefined) {
            hashTable[nums[i]] = 1;
        } else {
            hashTable[nums[i]]++;
        }
    }
    for(let i in hashTable) {
        if(hashTable[i] == 1) {
            return i;
        }
    }
};
// nums =[4,1,2,1,2] 输出 4
// 0
// 0^4 = 4
// 4^1 = 5
// 5^2 = 7
// 7^1 = 6
// 6^2 = 4
var singleNumber = function(nums{
    return nums.reduce((sum,cur)=>{
        return sum^cur
    }, 0)
    
};

五、实战:从零构建位运算权限系统

5.1 基础版权限控制

// 权限定义(使用左移生成唯一掩码)
const READ = 1 << 0;   // 0b0001
const WRITE = 1 << 1;  // 0b0010
const DELETE = 1 << 2// 0b0100
// 用户权限组合
let userPermissions = READ | WRITE; // 0b0011
// 高阶组件权限校验
const withAuth = required => WrappedComponent => props => 
    (userPermissions & required) === required 
        ? <WrappedComponent {...props} />  
        : <Redirect to="/403" />;
// 使用示例
const AdminPanel = withAuth(WRITE | DELETE)(() => <div>敏感操作区</div>);

5.2 进阶版权限控制

// 权限池扩展
const permissions = {
    READ1 << 0,
    WRITE1 << 1,
    DELETE1 << 2,
    MANAGER1 << 3
};
// 权限动态处理器
class PermissionManager {
    constructor() {
        this._flags = 0;
    }
    grant(perm) {
        this._flags |= perm; // 按位与:只有当两个二进制位都为 1 时,结果才为 1,否则为 0。
        return this;
    }
    revoke(perm) {
        this._flags &= ~perm; // 按位非~:将所有二进制位取反,然后与原值进行按位与&。
        return this;
    }
    toggle(perm) {
        this._flags ^= perm; //  按位异或^:当两个二进制位不同时,结果为 1;相同则为 0。
        return this;
    }
    has(perm) {
        return (this._flags & perm) === perm;
    }
}
// 使用示例
const user = new PermissionManager().grant(permissions.READ);
user.grant(permissions.WRITE);
console.log(user.has(permissions.READ | permissions.WRITE)); // true
user.toggle(permissions.WRITE);
console.log(user.has(permissions.WRITE)); // false

5.3 优点和缺点

优点

📊 「性能与内存对比」

缺点

    可读性差

    权限移除的复杂性

    最大权限位限制

六、后续思考

能否结合位元算和传统方式,实现权限系统的混合架构设计

点击关注公众号,“技术干货” 及时达!

阅读原文

跳转微信打开

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

位运算 权限管理 框架源码 算法应用 权限系统
相关文章