单字段表示多个属性
回答
shell
# 为什么要用单字段表示多属性?
减少数据传输 / 存储体积(如接口返回、本地存储);
简化状态管理(避免多字段冗余);
提升运算效率(位运算比多字段判断更快)。
# 常见实现方式?
1. 转 字符串编码/解码」:先编码把原始数据按照一定的规则分割成一个字符串整体,再解码使用的时候按照相同规则反解析字符串将其组合成对象
2. 转 JSON 字符串:JSON.stringify、JSON.parse 转为字符再转对象
3. 位掩码+数学运算:利用位掩码和数学运算将多个属性(权限、状态、等级)编码到一个数字中,以及如何从该数字中解码还原出原始属性
# 最后
“如果是布尔型的组合属性(如权限、功能开关),优先用位运算,效率高且扩展方便;如果是包含字符串 / 数字的复杂属性(如筛选条件、用户配置),用字符串编码或 JSON 字符串,兼顾可读性和结构化。”方案一:字符串编码(分隔符 / 固定格式)
js
// 1. 编码:单字符串表示“类型+范围+排序”三个属性(用|分隔)
const encodeFilter = (type, min, max, sort) => {
return `${type}|${min}-${max}|${sort}`;
};
const filterStr = encodeFilter('product', 10, 100, 'price_desc'); // "product|10-100|price_desc"
// 2. 解码:解析单字符串为多属性
const decodeFilter = (str) => {
const [type, range, sort] = str.split('|');
const [min, max] = range.split('-').map(Number);
return { type, min, max, sort };
};
const filterObj = decodeFilter(filterStr);
console.log(filterObj); // { type: 'product', min: 10, max: 100, sort: 'price_desc' }方案二:JSON 字符串
js
// 编码:单字符串表示多属性
const userConfig = { theme: 'dark', fontSize: 16, autoSave: true };
const configStr = JSON.stringify(userConfig); // "{"theme":"dark","fontSize":16,"autoSave":true}"
// 解码:还原为多属性对象
const configObj = JSON.parse(configStr);
console.log(configObj.fontSize); // 16方案三:位掩码+数学运算
&:按位与,操作的是位(整数),返回的是一个整数。
&&:逻辑与,操作的是布尔值(true/false),返回的是一个布尔值,并且具有短路特性(如果左边为假,右边不会执行)。
js
// 1. 定义常量
const Permission = { ADD: 1, DELETE: 2, EDIT: 4, READ: 8 };
const Status = { ENABLE: 16, DISABLE: 0 };
// 2. 编码:单数字表示多属性
const encodeUserAttr = (permissions, status, level) => {
const permValue = Object.values(permissions).reduce((a, b) => a | b, 0);
return permValue + status + level * 100;
};
// 3. 示例:将 增+查权限、启用状态、2级会员 属性编码得到最终编码结果为255
const userAttr = encodeUserAttr([Permission.ADD, Permission.READ], Status.ENABLE, 2);
console.log(userAttr); // 1+8+16 + 2*100 = 225(单字段)
// 4. 解码
const decodeUserAttr = (num) => {
const level = Math.floor(num / 100); // 会员等级 2
const rest = num % 100; // 权限+状态 25
const status = rest & Status.ENABLE ? '启用' : '禁用';
// & 是按位与运算符,常用于检查某个二进制位是否为 1。
// Status.ENABLE 应该是一个位掩码(如 0b01 或 0b10),它只在其对应的状态位上为 1,其他位为 0。
// rest & Status.ENABLE 的结果:
// 如果 rest 中对应 Status.ENABLE 的位是 1,则结果非零(真),表示“启用”;
// 如果该位是 0,则结果为零(假),表示“禁用”。
const permissions = [];
if (rest & Permission.ADD) permissions.push('增');
if (rest & Permission.DELETE) permissions.push('删');
if (rest & Permission.EDIT) permissions.push('改');
if (rest & Permission.READ) permissions.push('查');
return { level, status, permissions };
};
// 5. 示例:225 解码为 { level:2, status:'启用', permissions:['增','查'] }
console.log(decodeUserAttr(225));
// { level:2, status:'启用', permissions:['增','查'] }什么是按位掩码与数学运算
shell
# 十进制转二进制
将十进制数不断除以 2,记录每次的余数,直到商为 0,然后将余数从下往上排列。
# 以 5 转二进制 101 为例
步骤 计算 商 余数
1 5 ÷ 2 2 1
2 2 ÷ 2 1 0
3 1 ÷ 2 0 1
# 按位与 & 运算
const status = rest & Status.ENABLE ? '启用' : '禁用';
const status = 25 & 16 ? '启用' : '禁用';
25 转 二进制 10011
步骤 计算 商 余数
1 25 ÷ 2 12 1
2 12 ÷ 2 6 0
3 6 ÷ 2 3 0
4 3 ÷ 2 1 1
5 1 ÷ 2 0 1
16 转 二进制 00001
步骤 计算 商 余数
1 16 ÷ 2 8 0
2 8 ÷ 2 4 0
3 4 ÷ 2 2 0
4 2 ÷ 2 1 0
5 1 ÷ 2 0 1
25 & 16 的结果是 10011 和 00001 位数相等的结果为 00001 转为 10 进制结果为 1
也就是 25 & 16 等于 1
// 示例1:5 & 3
// 5 的二进制:0101
// 3 的二进制:0011
// 按位与结果:0001 (十进制1)
console.log(5 & 3); // 输出: 1
// 示例2:12 & 5
// 12的二进制:1100
// 5 的二进制:0101
// 按位与结果:0100 (十进制4)
console.log(12 & 5); // 输出: 4