位运算经典案例
权限管理
这是一个基于二进制位运算,并采用权限位掩码实现的轻量级用户权限管理工具。
该工具有以下特点:
- 核心基于 CPU 原生位运算(按位与、或、非、异或),权限管理瞬时完成
- 用单个数字存储所有权限,体积极小、传输与存储极高效
- 添加、删除、切换、判断全案使用统一位运算逻辑,确保 100% 无冲突
- 自动校验权限合法性,杜绝无效权限
- 支持批量操作、链式调用、权限名解析展示
- 无依赖、体积小、逻辑健壮,可直接用于前后端权限系统
js
/**
* ================================================
* User 权限管理类(位运算实现 · 高性能 · 工程化)
* 核心原理:用一个数字存储所有权限,每一位二进制代表一种权限
* 优点:存储小、速度快、功能强、无权限冲突
* ================================================
*/
class User {
// ================ 静态权限常量定义 ================
/**
* 权限位掩码(使用 Object.freeze 冻结,只读不可修改)
* 1 << n:将数字 1 左移 n 位,生成唯一不重复的权限制
* 每一种权限独占一个二进制位,永远不会冲突
*/
static Permissions = Object.freeze({
READ: 1 << 0, // 读权限:0001 → 1
WRITE: 1 << 1, // 写权限:0010 → 2
DELETE: 1 << 2, // 删除权限:0100 → 4
ADMIN: 1 << 3 // 管理员:1000 → 8
})
// ================ 私有静态工具(外部不可访问) ================
/**
* 映射表:权限数字 → 权限名
* 私有属性 # 开头,外部不可访问、不可修改
* 本例中返回: { '1': 'READ', '2': 'WRITE', '4': 'DELETE', '8': 'ADMIN' }
* @private
*/
static #PermissionMap = Object.freeze(
Object.fromEntries(
Object.entries(User.Permissions).map(([name, value]) => [value, name])
)
)
/**
* 合法权限值集合(用于校验传入的权限是否有效)
* 本例中返回:Set(4) { 1, 2, 4, 8 }
* @private
*/
static #ValidPermissions = new Set(Object.values(User.Permissions))
// ================ 构造函数 ================
constructor() {
// 存储当前用户所有权限(初始 0,即无任何权限)
this.permissions = 0
}
// ================ 私有校验方法 ================
/**
* 校验权限是否合法(防止乱传数字导致权限异常)
* @param {number} perm 待校验权限值
* @return {boolean} 是否合法
* @private
*/
#isValidPerm(perm) {
return User.#ValidPermissions.has(perm)
}
// ================ 公共权限操作方法 ================
/**
* 添加权限
* 按位或 |:有 1 则 1,不影响其他位
* @param {number} permissions 可传入多个权限
* @returns {User} 实例自身,支持链式调用
*/
addPermission(...permissions) {
permissions.forEach(perm => {
if (!this.#isValidPerm(perm)) return this // 非法权限直接返回
this.permissions |= perm
})
return this
}
/**
* 移除权限
* 按位与 & + 按位非 ~:只清空目标位
* @param {number} permissions 可传入多个权限
* @returns {User} 实例自身,支持链式调用
*/
removePermission(...permissions) {
permissions.forEach(perm => {
if (!this.#isValidPerm(perm)) return this
this.permissions &= ~perm
})
return this
}
/**
* 切换权限
* 按位异或 ^:相同为 0(有则删),不同为 1(无则加)
* @param {number} permissions 可传入多个权限
* @returns {User} 实例自身,支持链式调用
*/
togglePermission(...permissions) {
permissions.forEach(perm => {
if (!this.#isValidPerm(perm)) return this
this.permissions ^= perm
})
return this
}
/**
* 清空所有权限
* @returns {User} 实例自身,支持链式调用
*/
clearPermissions() {
this.permissions = 0
return this
}
/**
* 检查是否拥有某个权限
* @param {number} permission
* @returns {boolean}
*/
hasPermission(permission) {
if (!this.#isValidPerm(permission)) return false
return (this.permissions & permission) === permission
}
/**
* 检查是否拥有【全部】传入权限
* @param {number} perms 可传入多个权限
* @returns {boolean}
*/
hasAllPermissions(...perms) {
return perms.every(perm => this.hasPermission(perm))
}
/**
* 检查是否拥有【任意一个】传入权限
* @param {number} perms 可传入多个权限
* @returns {boolean}
*/
hasAnyPermissions(...perms) {
return perms.some(perm => this.hasPermission(perm))
}
// ================ 增强功能 ================
/**
* 快速判断是否是管理员
* @returns {boolean}
*/
isAdmin() {
return this.hasPermission(User.Permissions.ADMIN)
}
/**
* 获取当前权限名称数组(用于页面展示)
* @returns {string[]} 如 ['READ', 'ADMIN']
*/
getPermissionNames() {
return Object.values(User.Permissions)
.filter(val => (this.permissions & val) === val)
.map(val => User.#PermissionMap[val])
}
}
// ================ 使用示例 ================
// 1. 创建用户
const user = new User()
// 2. 解构权限(方便使用)
const { READ, WRITE, DELETE, ADMIN } = User.Permissions
// 3. 添加权限
user.addPermission(READ)
user.addPermission(WRITE, ADMIN) // 批量添加
// 4. 查看权限
console.log(user.getPermissionNames()) // ['READ', 'WRITE', 'ADMIN']
// 5. 校验权限
console.log(user.isAdmin()) // true
console.log(user.hasPermission(READ)) // true
console.log(user.hasAllPermissions(READ, WRITE, DELETE, ADMIN)) // false
console.log(user.hasAnyPermissions(READ, WRITE, DELETE, ADMIN)) // true
// 6. 移除/切换权限
user.removePermission(WRITE)
user.togglePermission(DELETE)
console.log(user.getPermissionNames()) // ['READ', 'DELETE', 'ADMIN']
// 7. 清空权限
user.clearPermissions()
console.log(user.getPermissionNames()) // []加密解密
这是一个基于异或运算,并采用 Base64 编码实现的轻量级加密解密工具。
该工具有以下特点:
- 核心基于 CPU 原生位运算(异或),加密解密瞬时完成
- 方法调用简单,无需复杂配置
- Base64 编码后密文可安全存储,并支持中文
- 加密解密共用核心逻辑,确保原文 100% 无损耗还原
- 自动兼容浏览器与 Node 环境
- 无依赖、体积小、逻辑健壮,可直接集成到项目中
注意
该加密工具仅适用于非敏感数据的加密混淆,不适用于用户密码、支付信息、隐私数据等敏感场景。因为其加密强度较低,容易被暴力破解。生产环境应使用官方加密算法,如浏览器中的 Web Crypto API,或 Node 环境下的 crypto 模块(AES、RSA 等)。
js
/**
* ================================================
* 异或加密 + Base64 编码
* 核心原理:明文 ^ 密钥 = 密文;密文 ^ 密钥 = 明文
* 支持:浏览器环境 + Node.js 环境
* ================================================
*/
class SimpleXORCipher {
// ================ 构造函数 ================
/**
* 初始化加密密钥
* @param {number} key 必须是数字,如 85、123、0x55
*/
constructor(key) {
// 把传入的密钥保存到实例属性,供加密解密使用
this.key = key
}
// ================ 私有方法 ================
/**
* 【核心方法】异或转换:加密和解密共用的逻辑(异或特性)
* 明文 ^ 密钥 = 密文;密文 ^ 密钥 = 明文
* 原理:密文 ^ 密钥 = 明文 ^ 密钥 ^ 密钥 = 明文 ^ (密钥 ^ 密钥) = 明文 ^ 0 = 明文
* @param {string} str 需要转换的字符串(原文/密文)
* @returns {string} 异或转换后的字符串
*/
#xorTransform(str) {
let result = ''
// 遍历传入字符串的每个字符
for (let i = 0; i < str.length; i++) {
// 把字符转成 Unicode 编码(数字),然后和密钥异或,再转回字符
const charCode = str.charCodeAt(i) ^ this.key
result += String.fromCharCode(charCode)
}
// 返回异或完成的字符串
return result
}
// ================ 公共方法 ================
/**
* 加密方法:异或处理 + Base64 编码
* @param {string} text 原始明文(如 'Hello World','你好,世界')
* @returns {string} Base64 格式的加密字符串
*/
encrypt(text) {
// 1. 使用异或算法对原文进行加密
const xorStr = this.#xorTransform(text)
// 2. 判断环境:浏览器 / Node.js
if (typeof btoa === 'function') {
// 浏览器环境(使用 btoa 进行 Base64 编码)
// 使用 Uint8Array 处理编码,避免中文报错,符合现代标准
const uint8Array = new TextEncoder().encode(xorStr)
const binaryStr = String.fromCharCode(...uint8Array)
return btoa(binaryStr)
} else {
// Node.js 环境(使用 Buffer 进行 Base64 编码)
return Buffer.from(xorStr).toString('base64')
}
}
/**
* 解密方法:Base64 解码 + 异或还原
* @param {string} encryptedText Base64 格式的解密字符串
* @returns {string} 解密后的原始明文
*/
decrypt(encryptedText) {
let xorStr
if (typeof atob === 'function') {
const binaryStr = atob(encryptedText)
const uint8Array = new Uint8Array(binaryStr.length)
for (let i = 0; i < binaryStr.length; i++) {
uint8Array[i] = binaryStr.charCodeAt(i)
}
xorStr = new TextDecoder().decode(uint8Array)
} else {
xorStr = Buffer.from(encryptedText, 'base64').toString()
}
return this.#xorTransform(xorStr)
}
}
// ================ 使用示例 ================
// 1. 创建加密实例(数字即可,推荐 1~255 之间)
const cipher = new SimpleXORCipher(85)
// 2. 原始文本
const original = 'Hello World 你好,世界!'
// 3. 加密:得到 Base64 格式字符串
const encrypted = cipher.encrypt(original)
// 4. 解密:还原原始文本
const decrypted = cipher.decrypt(encrypted)
// 输出结果
console.log('原文:', original) // 'Hello World 你好,世界!'
console.log('加密后:', encrypted) // 'HTA5OTp1AjonOTF15Ly15aSo772Z5LmD55SZ772U'
console.log('解密后:', decrypted) // 'Hello World 你好,世界!'颜色处理
这是一个基于 32 位为预算,并采用标准 AARRGGBB 颜色格式实现的轻量级颜色处理工具。
该工具有以下特点:
- 核心基于 CPU 原生委员算,颜色打包、解析、调节瞬时完成
- 方法调用简单,无需复杂配置,开箱即用
- 支持 32 位整数与 RGBA 颜色互换,并可安全存储与传输
- 打包(编码)解析(解码)共用位运算核心逻辑,确保颜色值 100% 无损还原
- 自动兼容浏览器与 Node 环境
- 无依赖、体积小、逻辑健壮,自带数值合法性校验,可直接集成到项目中
- 支持颜色亮度调节、多色混合、CSS 格式/16 进制格式一键转换
js
/**
* ================================================
* 32 位位运算颜色处理(AARRGGBB 格式)
* 核心原理:移位、与、或运算打包/解析颜色,保证色值在 0~255
* 功能:颜色封装、打包/解析、亮度调节、颜色混合、色值转换等
* ================================================
*/
class Color {
// ================ 私有属性 ================
#r // 红色通道 0~255
#g // 绿色通道 0~255
#b // 蓝色通道 0~255
#a // 透明度通道 0~255
#int32Cache = null // 缓存 32 位整数颜色值,避免重复计算
// ================ 构造函数 ================
/**
* 初始化颜色实例
* @param {number} r 红色通道 0~255
* @param {number} g 绿色通道 0~255
* @param {number} b 蓝色通道 0~255
* @param {number} a 透明度通道 0~255,默认 255(不透明)
*/
constructor(r, g, b, a = 255) {
// 对每个通道执行合法性校验,确保在 0~255
this.#r = Color.#clamp(r)
this.#g = Color.#clamp(g)
this.#b = Color.#clamp(b)
this.#a = Color.#clamp(a)
}
// ================ 私有方法 ================
/**
* 把任意值转换成合法的 0~255 颜色整数
* @param {*} value 任意原始值
* @returns {number} 合法颜色值
*/
static #clamp(value) {
// 强制转数字 → 非法值兜底 0 → 四舍五入取整 → 超过 255 封顶 → 负数保底 0
return Math.max(0, Math.min(255, Math.round(Number(value) || 0)))
}
/**
* 计算颜色视觉亮度(供灰度、深浅色判断复用)
* 标准公式:亮度 = R * 0.299 + G * 0.587 + B * 0.114
* @returns {number} 亮度值 0~255
*/
#getBrightness() {
// 采用了国际标准 REC.601 人眼加权亮度公式,用来计算一个颜色看起来有多亮
// 人眼对绿色最敏感(看起来最亮)、红色次之(中等)、蓝色最不敏感(最暗)
// 权重比例:红 29.9%,绿 58.7%,蓝 11.4%
return (this.#r * 299 + this.#g * 587 + this.#b * 114) / 1000
}
// ================ 实例方法(颜色操作) ================
/**
* 克隆当前颜色,返回一个数据完全相同的新实例
* @returns {Color} 新的颜色实例
*/
clone() {
return new Color(this.#r, this.#g, this.#b, this.#a)
}
/**
* 调整颜色的整体亮度
* @param {number} factor 亮度系数,小于 1 变暗,大于 1 变亮,自动限制为非负数
* @returns {Color} 调整后的新颜色实例
*/
adjustBrightness(factor = 0.5) {
// 确保系数不为负数
const f = Math.max(0, Number(factor) || 0)
// 每个颜色通道乘以系数,透明度不变
return new Color(this.#r * f, this.#g * f, this.#b * f, this.#a)
}
/**
* 快速将颜色调暗(亮度降低 50%)
* @returns {Color} 调暗后的新颜色实例
*/
darken() {
// 直接复用亮度调节方法,乘以 0.5
return this.adjustBrightness(0.5)
}
/**
* 快速将颜色调亮(亮度提升 30%,安全不溢出)
* @returns {Color} 调亮后的新颜色实例
*/
lighten() {
// 安全提亮 1.3 倍,避免超过 255
return this.adjustBrightness(1.3)
}
/**
* 判断当前颜色是否为深色(用于自动适配文字颜色)
* @returns {boolean}
*/
isDark() {
// 亮度小于 128 判定为深色
return this.#getBrightness() < 128
}
/**
* 判断当前颜色是否为浅色
* @returns {boolean}
*/
isLight() {
// 浅色就是非深色
return !this.isDark()
}
/**
* 获取当前颜色的反色(互补色)
* @returns {Color} 反色后的新颜色实例
*/
invert() {
// 反色 = 255 - 当前值,透明度不变
return new Color(255 - this.#r, 255 - this.#g, 255 - this.#b, this.#a)
}
/**
* 设置颜色的透明度
* @param {number} alpha 透明度值(会自动裁剪为 0~255)
* @returns {Color} 新颜色实例
*/
setAlpha(alpha) {
alpha = Color.#clamp(alpha)
// RGB 不变,只替换透明度
return new Color(this.#r, this.#g, this.#b, alpha)
}
/**
* 将当前颜色转为灰度色(黑白)
* @returns {Color} 新的灰度颜色实例
*/
grayscale() {
// 用亮度值作为 RGB 三个通道,实现黑白效果
const gray = this.#getBrightness()
return new Color(gray, gray, gray, this.#a)
}
/**
* 判断与另一个颜色是否完全相等
* @param {Color} other 另一个颜色实例
* @returns {boolean}
*/
equals(other) {
// 边界判断
if (!other || !(other instanceof Color)) return false
// 四个通道必须全部相等
return (
this.#r === other.#r &&
this.#g === other.#g &&
this.#b === other.#b &&
this.#a === other.#a
)
}
// ================ 实例方法(格式转换) ================
/**
* 打包为 32 位无符号整数,标准格式 AARRGGBB
* @returns {number} 32 位整型颜色值
*/
toInt32() {
// 已有缓存直接返回,避免重复执行位运算
if (this.#int32Cache) return this.#int32Cache
// 按位偏移 + 按位或,拼接成 AARRGGBB 32 位颜色值
const val =
((this.#a << 24) | (this.#r << 16) | (this.#g << 8) | this.#b) >>> 0
// 缓存计算结果,提升后续重复调用性能
this.#int32Cache = val
return val
}
/**
* 转换为标准 CSS rgba 格式字符串
* @returns {string} 如 rgba(255, 0, 0, 1.000)
*/
toCss() {
// 透明度从 0~255 转为 0~1,并保留 3 位小数
const alpha = (this.#a / 255).toFixed(3)
// 拼接成 CSS 标准格式
return `rgba(${this.#r}, ${this.#g}, ${this.#b}, ${alpha})`
}
/**
* 转换为十六进制颜色字符串
* @param {boolean} includeAlpha 是否包含透明度通道(默认不包含)
* @returns {string} 如 #FF0000 或 #FFFF0000
*/
toHex(includeAlpha = false) {
// 先拿到 32 位整数,再转 8 位十六进制字符串
const hex = this.toInt32().toString(16).padStart(8, '0')
// 根据是否需要透明通道返回对应格式
return includeAlpha
? `#${hex.slice(2) + hex.slice(0, 2)}`
: `#${hex.slice(2)}`
}
/**
* 转为易读的字符串格式(用于日志打印)
* @returns {string}
*/
toString() {
return `Color(r: ${this.#r}, g: ${this.#g}, b: ${this.#b}, a: ${this.#a})`
}
/**
* 转为 JSON 序列化对象
* @returns {object}
*/
toJSON() {
return { r: this.#r, g: this.#g, b: this.#b, a: this.#a }
}
// ================ 只读访问器 ================
get r() {
return this.#r
}
get g() {
return this.#g
}
get b() {
return this.#b
}
get a() {
return this.#a
}
// ================ 静态方法(颜色操作) ================
/**
* 混合两种颜色,返回中间过渡色
* @param {Color} c1 第一种颜色
* @param {Color} c2 第二种颜色
* @param {number} factor 混合比例 0~1
* @returns {Color} 混合后的新颜色实例
*/
static blend(c1, c2, factor = 0.5) {
// 类型校验
if (!(c1 instanceof Color) || !(c2 instanceof Color)) {
throw new Error('必须传入 Color 实例')
}
// 限制混合比例在 0~1
// 颜色1 权重 = 1 - f,颜色 2 权重 = f
// 即 f + (1 - f) = 1,两种颜色的权重加起来 = 100%
const f = Math.max(0, Math.min(1, Number(factor) || 0.5))
// 线性混合(lerp)公式:颜色1 * 权重1 + 颜色2 * 权重2
let r = c1.r * (1 - f) + c2.r * f // 红色通道混合
let g = c1.g * (1 - f) + c2.g * f // 绿色通道混合
let b = c1.b * (1 - f) + c2.b * f // 蓝色通道混合
let a = c1.a * (1 - f) + c2.a * f // 透明度通道混合
// 视觉提亮(专业伽马矫正,解决混合偏暗)
// 只对中间混合色生效,0 和 1 时不处理
if (f > 0.01 && f < 0.99) {
r = Math.sqrt(r / 255) * 255
g = Math.sqrt(g / 255) * 255
b = Math.sqrt(b / 255) * 255
}
// 返回新颜色实例
return new Color(r, g, b, a)
}
// ================ 静态方法(格式转换) ================
/**
* 将 32 位整数(AARRGGBB)解析为颜色实例
* @param {number} color 32 位整型颜色值
* @returns {Color} 新的颜色实例
*/
static fromInt32(color) {
const num = Number(color) || 0
const mask = 0xff
return new Color(
(num >> 16) & mask, // 红色
(num >> 8) & mask, // 绿色
num & mask, // 蓝色
(num >> 24) & mask // 透明度
)
}
static fromHex(hexStr) {
// 非字符串直接返回黑色
if (typeof hexStr !== 'string') return new Color(0, 0, 0)
// 去掉空格与 # 号
let hex = hexStr.trim().replace('#', '')
// 非法长度直接返回黑色
if (![3, 6, 8].includes(hex.length)) return new Color(0, 0, 0)
// 3 位简写转 6 位
if (hex.length === 3) {
hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2]
}
// 转成数字
const num = parseInt(hex, 16)
// 转失败返回黑色
if (isNaN(num)) return new Color(0, 0, 0)
// 8 位带透明度,6 位默认不透明
// 使用按位或 | 将 #RRGGBB 转为 #FFRRGGBB(即最高 8 位为 FF,不透明)
return hex.length === 8
? Color.fromInt32(num)
: Color.fromInt32(num | 0xff000000)
}
}
// ================ 使用示例 ================
console.log('1. 创建基础颜色')
const red = new Color(255, 0, 0)
const green = new Color(0, 255, 0)
const blue = new Color(0, 0, 255)
const white = new Color(255, 255, 255)
const black = new Color(0, 0, 0)
console.log('红色实例:', red.toString()) // Color(r: 255, g: 0, b: 0, a: 255)
console.log('绿色实例:', green.toString()) // Color(r: 0, g: 255, b: 0, a: 255)
console.log('蓝色实例:', blue.toString()) // Color(r: 0, g: 0, b: 255, a: 255)
console.log('\n2. 颜色格式转换')
console.log('红色 → CSS:', red.toCss()) // rgba(255, 0, 0, 1.000)
console.log('红色 → Hex:', red.toHex()) // #ff0000
console.log('红色 → 带透明度 Hex:', red.toHex(true)) // #ff0000ff
console.log('红色 → 32位整数:', red.toInt32()) // 4294901760
console.log('\n3. 亮度调节')
console.log('红色调亮:', red.lighten().toHex()) // #ff0000
console.log('红色调暗:', red.darken().toHex()) // #800000
console.log('\n4. 反色与灰度')
console.log('红色反色:', red.invert().toHex()) // #00ffff
console.log('红色灰度:', red.grayscale().toHex()) // #4c4c4c
console.log('\n5. 设置透明度')
console.log('红色半透明:', red.setAlpha(128).toHex(true)) // #ff000080
console.log('\n6. 判断深浅色')
console.log('红色是否深色:', red.isDark())
console.log('白色是否浅色:', white.isLight())
console.log('\n7. 从十六进制解析颜色')
const hexColor = Color.fromHex('#42b983')
console.log('#42b983 → 实例:', hexColor.toString())
console.log('#42b983 是否深色:', hexColor.isDark())
console.log('\n8. 颜色混合')
const purple = Color.blend(red, blue)
const yellow = Color.blend(red, green)
console.log('红 + 蓝 = 紫', purple.toHex()) // #b400b4
console.log('红 + 绿 = 黄', yellow.toHex()) // #b4b400
console.log('\n9. 从 32 位整数恢复颜色')
const intColor = Color.fromInt32(0xffff0000)
console.log('0xFFFF0000 →', intColor.toHex()) // #ff0000
console.log('\n10. 克隆与相等判断')
const redClone = red.clone()
console.log('克隆红色与原红色是否相等:', red.equals(redClone)) // true
console.log('红色与蓝色是否相等:', red.equals(blue)) // false