Skip to the content.

一、原因

日常项目中可能会遇到的场景,比如

1、记录用户完成的多个步骤
2、用户提交信息后,后台审核驳回的多个原因字段
...

这些如果用多个字段表示会非常麻烦,而且不好记,多余

我们可以使用二进制的形式来包含不同的状态


二、使用方式

/**
 * description:根据 二进制转换成的 10 进制,经过对比得到下一个未完成的步骤
 * @param {Number} stepBinaryToTenHex 二进制转换的10进制值
 * @param {Number} maxStep 最大可记录步骤数,默认为 8
 * */
function calcNextStep(stepBinaryToTenHex, maxStep = 8) {
    // 默认步数为第 1 步
    let power = 1
    for (let step = 1; step <= maxStep; step++) {
        if ((stepBinaryToTenHex & power) === 0) {
            // 若 `与操作` 结果为 0
            // 说明当次步骤还未完成,返回该步骤
            return step
        }
        // 若 `与操作` 结果不为 0,说明是已完成
        // 继续增大 2 的幂次方
        power *= 2
    }
}
完成第一步0000 0001 --> 1     calcNextStep(1)     // 下一个未完成步骤为:2
完成第二步0000 0011 --> 3     calcNextStep(3)     // 下一个未完成步骤为:3
完成第三步0000 0111 --> 7     calcNextStep(7)     // 下一个未完成步骤为:4
完成第四步0000 1111 --> 15    calcNextStep(15)    // 下一个未完成步骤为:5
完成第五步0001 1111 --> 31    calcNextStep(31)    // 下一个未完成步骤为:6
完成第六步0011 1111 --> 63    calcNextStep(63)    // 下一个未完成步骤为:7
完成第七步0111 1111 --> 127   calcNextStep(127)   // 下一个未完成步骤为:8
完成第八步1111 1111 --> 255   calcNextStep(255)   // undefined

注意: stepBinaryToTenHex 才是前端和后端存储的值,并不是直接使用二进制保存


三、原理

1. 表示

用 0000 0000 表示 1 - 8 个步骤

从右到左,依次表示 第 1 步第 8 步 的完成情况

二进制位上为 1 的表示该步骤已经完成,为 0 表示未完成

1:  0000 0001
2:  0000 0011
3:  0000 0111
4:  0000 1111
5:  0001 1111
6:  0011 1111
7:  0111 1111
8:  1111 1111

假如:我们此时走到第四步

// step 为 4
// stepBinary 二进制 为 00001111
// stepBinaryToTenHex 为 15
4  00001111


2. 计算

那么我们想知道还未开始的 step 是多少?
可以使用 与操作(&)

与操作的规则是

0 & 0 = 0
0 & 1 = 0
1 & 1 = 1

下面是 2 的递增次方值,转换成 2 进制 powerBinary 后都只有一个 1

根据 与操作 的特点,我们可以将 stepBinarypowerBinary 进行 与操作

得到的结果为 0,则说明该步没有完成

1:     0000 0001
2:     0000 0010
4:     0000 0100
8:     0000 1000
16:    0001 0000
32:    0010 0000
64:    0100 0000
128:   1000 0000


3. 例子

比如 第 4 步相应的的二进制和 powerBinary 依次 与操作

4:  0000 1111
2^1: 0000 0001 --> 结果为:  0000 0001
2^2: 0000 0010 --> 结果为:  0000 0010
2^3: 0000 0100 --> 结果为:  0000 0100
2^4: 0000 1000 --> 结果为:  0000 1000
2^5: 0001 0000 --> 结果为:  0000 0000 此处 `与操作` 结果为 0,说明未完成

由此可以得到结论: 第五步没有完成

用 javascript 实现如下

/**
 * description:根据 二进制转换成的 10 进制,经过对比得到下一个未完成的步骤
 * @param {Number} stepBinaryToTenHex 二进制转换的10进制值
 * @param {Number} maxStep 最大可记录步骤数,默认为 8
 * */
function calcNextStep(stepBinaryToTenHex, maxStep = 8) {
    // 默认步数为第 1 步
    let power = 1
    for (let step = 1; step <= maxStep; step++) {
        if ((stepBinaryToTenHex & power) === 0) {
            // 若 `与操作` 结果为 0
            // 说明当次步骤还未完成,返回该步骤
            return step
        }
        // 若 `与操作` 结果不为 0,说明是已完成
        // 继续增大 2 的幂次方
        power *= 2
    }
}
calcNextStep(15) // 5