前面咱们已经了解了六大位操做符(&
|
~
^
<<
>>
)的用法(javascript 位运算),也整理了一些经常使用的位运算操做(经常使用位运算整理),本文咱们继续深刻位运算,来了解下二进制的经典应用-标志位与掩码。javascript
位运算常常被用来建立、处理以及读取标志位序列——一种相似二进制的变量。虽然可使用变量代替标志位序列,可是这样能够节省内存(1/32)。html
例若有4个标志位:java
标志位经过位序列DCBA来表示,当一个位置被置为1时,表示有该项,置为0时,表示没有该项。例如一个变量flag=9,二进制表示为1001,就表示咱们有D和A。app
掩码 (bitmask) 是一个经过与/或来读取标志位的位序列。典型的定义每一个标志位的原语掩码以下:code
var FLAG_A = 1; // 0001 var FLAG_B = 2; // 0010 var FLAG_C = 4; // 0100 var FLAG_D = 8; // 1000
新的掩码能够在以上掩码上使用逻辑运算建立。例如,掩码 1011 能够经过 FLAG_A、FLAG_B 和 FLAG_D 逻辑或获得:htm
var mask = FLAG_A | FLAG_B | FLAG_D; // 0001 | 0010 | 1000 => 1011
某个特定的位能够经过与掩码作逻辑与运算获得,经过与掩码的与运算能够去掉无关的位,获得特定的位。例如,掩码 0100 能够用来检查标志位 C 是否被置位:(核心就是判断某位上的数 参考经常使用位运算整理 下同)blog
// 若是咱们有 banana if (flags & FLAG_C) { // 0101 & 0100 => 0100 => true // do stuff }
一个有多个位被置位的掩码表达任一/或者的含义。例如,如下两个表达是等价的:ip
// 若是咱们有 apple 或者 banana 至少一个 // (0101 & 0010) || (0101 & 0100) => 0000 || 0100 => true if ((flags & FLAG_B) || (flags & FLAG_C)) { // do stuff } var mask = FLAG_B | FLAG_C; // 0010 | 0100 => 0110 if (flags & mask) { // 0101 & 0110 => 0100 => true // do stuff }
能够经过与掩码作或运算设置标志位,掩码中为 1 的位能够设置对应的位。例如掩码 1100 可用来设置位 C 和 D:(核心就是将某位变为1 )内存
// 咱们有 banana 和 pear var mask = FLAG_C | FLAG_D; // 0100 | 1000 => 1100 flags |= mask; // 0101 | 1100 => 1101
能够经过与掩码作与运算清除标志位,掩码中为 0 的位能够设置对应的位。掩码能够经过对原语掩码作非运算获得。例如,掩码 1010 能够用来清除标志位 A 和 C :(核心就是将某位变为0)get
// 咱们没有 orange 也没有 banana var mask = ~(FLAG_A | FLAG_C); // ~0101 => 1010 flags &= mask; // 1101 & 1010 => 1000
如上的掩码一样能够经过 ~FLAG_A & ~FLAG_C 获得(德摩根定律):
// 咱们没有 orange 也没有 banana var mask = ~FLAG_A & ~FLAG_C; flags &= mask; // 1101 & 1010 => 1000
标志位可使用异或运算切换。全部值为 1 的为能够切换对应的位。例如,掩码 0110 能够用来切换标志位 B 和 C:(核心就是将某位取反)
// 若是咱们之前没有 apple ,那么咱们如今有 apple // 可是若是咱们已经有了一个,那么如今没有了 // 对 banana 也是相同的状况 var mask = FLAG_B | FLAG_C; flags = flags ^ mask; // 1100 ^ 0110 => 1010
最后,全部标志位能够经过非运算翻转:
// entering parallel universe... flags = ~flags; // ~1010 => 0101