按位运算符

Operator Name Description
& AND 返回1当两者都为1时,即 1&1
| OR 返回1当两者任意有1时, 即 1|0,1|1,0|1
^ XOR 返回1当且仅有一个1时, 1^0, 0^1
~ NOT 反转
<< Zero fill left shift 通过从右推入零向左位移,并使最左边的位脱落。
>> Signed right shift 通过从左推入最左位的拷贝来向右位移,并使最右边的位脱落。
>>> Zero fill right shift 通过从左推入零来向右位移,并使最右边的位脱落。

Javascript32位按位运算数

  1. 0 => 00000000000000000000000000000000
  2. -1 => 11111111111111111111111111111111
  3. 2147483647 => 01111111111111111111111111111111
  4. -2147483648 => 10000000000000000000000000000000

~ 运算差异性

~5 = 00000000000000000000000000000101 
     11111111111111111111111111111010 = ~6

可理解为 ~A = -(A + 1)

>> 与 >>> 的区别

共同点都是向右位移

  • >> 是拷贝符号, 即向右位移时扩展符号位 0 或者 1
  • >>> 永远是拓展0
    -2 >> 1  => 11111110 -> 11111111  = -1  (最左补1)
    -2 >>> 1 => 11111110 -> 01111111  = 2147483647 (最左补0)
    

技巧使用

切换开关

var v = 1;

v ^= 1; // => 0
v ^= 1; // => 1
v ^= 1; // => 0
v ^= 1; // => 1

交换变量

var x = 1;
var y = -2;

x ^= y;
y ^= x;
x ^= y;

x; // => -2
y; // => 1

代替Math.pow

Math.pow(2, 12) === 1 << 12
// => true

判断是否2的幂方

v && !(v & (v - 1));

下一个2的幂方数

var v = 65; // unsigned integer;

const nextPowerOf2Number = (num) => {
  let next = num;
  next--;
  next |= next >> 1;
  next |= next >> 2;
  next |= next >> 4;
  next |= next >> 8;
  next |= next >> 16;
  ++next;
  return next;
};

console.log(nextPowerOf2Number(v)); // 128

判断是否包含负数

当 0 ^ -0 = 0 不可用

var x = 1;
var y = 1;

(x ^ y) < 0;
// => false

判断奇偶数

if (v & 1) {
  // v is odd
}
else {
  // v is even
}

整数乘除法

20.5 << 1; // <~> 20 * 2
// => 40

20.5 >> 1; // <~> 20 / 2
// => 10

不使用除法取模

当分母为 1<<s 值时

var n = 20;          // unsigned integer; numerator
var s = 3;           // unsigned integer; power of 2
var d = 1 << s;      // unsigned integer; d will be one of: 1, 2, 4, 8, 16, 32, ...
var m = n & (d - 1); // unsigned integer; m will be n % d

m === 20 % 8;
// => true

当分母为 (1<<s)-1 值时

var n = 20;           // unsigned integer; numerator
var s = 3;            // unsigned integer > 0; power of 2
var d = (1 << s) - 1; // unsigned integer; so d is either 1, 3, 7, 15, 31, ...).
var m;                // unsigned integer; n % d goes here.

for (m = n; n > d; n = m) {
  for (m = 0; n; n >>= s) {
    m += n & d;
  };
};

// Now m is a value from 0 to d,
// but since with modulus division we want m to be 0 when it is d.
m = (m == d) ? 0 : m;

m === 20 % 7;
// => true

代替Math.floor

var v = 3.14

Math.floor(3.14) === ~~3.14

代替Math.max

var x = 2410;
var y = 19;

Math.max(x, y) === (x ^ ((x ^ y) & -(x < y)));
// => true

Math.min(x, y) === (y ^ ((x ^ y) & -(x < y)));
// => true

rgb转hex

var color = { r: 186, g: 218, b: 85 };

var rgb2hex = function(r, g, b) {
  return '#' + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
}

rgb2hex(color.r, color.g, color.b);
// => '#bada55'

计算hex之间差值

var a = 0xF0; // 240
var b = 0xFF; // 255

~a & b;
// => 15

创建位数组

var num = 5;
var index = 0;
var mask = 128;

var bits = [];
while (mask > 0) {
  mask >>= 1;
  index++;
  bits.push((mask & num ? 1 : 0));
};

bits;
// => [0, 0, 0, 0, 0, 1, 0, 1]

parseInt(bits.join(''), 2);
// => 5

计算32位整数中的位

var v = 5;
var count; // accumulates the total bits set in v

for (count = 0; v; v >>= 1) {
  count += v & 1;
};

// The naive approach requires one iteration per bit, until no more bits are set.
// So on a 32-bit word with only the high set, it will go through 32 iterations.
var v = 5;
var count;

for (count = 0; v; count++) {
  v &= v - 1; // clear the least significant bit set
};

// Brian Kernighan's method goes through as many iterations as there are set bits.
// So if we have a 32-bit word with only the high bit set, then it will only go once through the loop.
var v = 5;
var count;

v = v - ((v >> 1) & 0x55555555);                        // reuse input as temporary
v = (v & 0x33333333) + ((v >> 2) & 0x33333333);         // temp
count = ((v + (v >> 4) & 0xF0F0F0F) * 0x1010101) >> 24; // count

Merge bits from two values according to a mask

var x;    // unsigned integer to merge in non-masked bits
var y;    // unsigned integer to merge in masked bits
var mask; // unsigned integer; 1 where bits from y should be selected; 0 where from x.
var r;    // unsigned integer; result of (x & ~mask) | (y & mask) goes here

r = x ^ ((x ^ y) & mask);

// This shaves one operation from the obvious way of combining two sets of bits according to a bit mask.

Test if the n-th bit is set

if (v & (1 << n)) {
  // n-th bit is set
}
else {
  // n-th bit is not set
}

点击更多 https://gist.github.com/everget/320499f197bc27901b90847bf9159164