我在JavaScript的哪儿使用按位运算符?


72

我读过“什么是按位运算符?” ,所以我知道什么是 按位运算符,但仍不清楚如何使用它们。谁能提供在JavaScript中有用的按位运算符的真实示例吗?

谢谢。

编辑:

深入研究jQuery源,我发现了几个使用按位运算符的地方,例如:(仅&运算符)

// Line 2756:
event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));

// Line 2101
var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1;

Answers:


71

例:

解析十六进制值以获得RGB颜色值。

var hex = 'ffaadd';
var rgb = parseInt(hex, 16); // rgb is 16755421


var red   = (rgb >> 16) & 0xFF; // returns 255
var green = (rgb >> 8) & 0xFF;  // 170
var blue  = rgb & 0xFF;     // 221  

这如何符合UTF-16?
塞巴斯蒂安·巴特

7
@SebastianBarth怎么回事?这段代码中没有字符编码与远程相关的部分。
hobbs

45

我在生产脚本中大量使用按位运算符进行数值转换,因为有时它们要比它们MathparseInt同等运算符快得多。

我要付出的代价是代码可读性。因此,我通常Math在开发中使用,而在生产中按位使用。

您可以在jsperf.com上找到一些性能技巧

正如你所看到的,浏览器不优化Math.ceilparseInt多年,所以我预测按位会更快和更短的方式来做事的furure也

进一步阅读...


奖励:小抄| 0:一个方便,快捷的方式转换成任何东西整数:

( 3|0 ) === 3;             // it does not change integers
( 3.3|0 ) === 3;           // it casts off the fractional part in fractionalal numbers
( 3.8|0 ) === 3;           // it does not round, but exactly casts off the fractional part
( -3.3|0 ) === -3;         // including negative fractional numbers
( -3.8|0 ) === -3;         // which have Math.floor(-3.3) == Math.floor(-3.8) == -4
( "3"|0 ) === 3;           // strings with numbers are typecast to integers
( "3.8"|0 ) === 3;         // during this the fractional part is cast off too
( "-3.8"|0 ) === -3;       // including negative fractional numbers
( NaN|0 ) === 0;           // NaN is typecast to 0
( Infinity|0 ) === 0;      // the typecast to 0 occurs with the Infinity
( -Infinity|0 ) === 0;     // and with -Infinity
( null|0 ) === 0;          // and with null,
( (void 0)|0 ) === 0;      // and with undefined
( []|0 ) === 0;            // and with an empty array
( [3]|0 ) === 3;           // but an array with one number is typecast to number
( [-3.8]|0 ) === -3;       // including the cast off of the fractional part
( [" -3.8 "]|0 ) === -3;   // including the typecast of strings to numbers
( [-3.8, 22]|0 ) === 0     // but an Array with several numbers is typecast to 0
( {}|0 ) === 0;                // an empty object is typecast to 0
( {'2':'3'}|0 ) === 0;         // or a not empty object
( (function(){})|0 ) === 0;    // an empty function is typecast to 0 too
( (function(){ return 3;})|0 ) === 0;

还有一些魔术:

3 | '0px' === 3;

或在高级模式下使用闭包编译器为您完成所有这些优化
Pawel

2
这不是一个好答案。乍一看,它看起来像是参考书,具有很多信息(我昨天也对此表示赞同),但是经过更彻底的研究,结果却并非如此。
德米特里·科罗廖夫

4
所有这20行左右的示例本可以用一个句子表示:按位运算符使用数字的32位,二进制补码big-endian(简称32位)表示,因此将转换它们的任何操作数根据以下规则将其转换为该格式:将数字从IEEE-754 64位格式转换为32位,然后将其他所有内容首先转换为ECMAScript规范中指定的数字(即,对于对象(即对象) ,数组,函数)(通过对其valueOf方法的调用),然后将该数字转换为32位格式
Dmitry Koroliov

1
您可以尝试以下操作:'use strict'; Function.prototype.valueOf = function() {return 2;};console.log(( (function(){})|0 ) === 0);,然后会看到最后两个示例不正确,依此类推。
德米特里·科罗廖夫

2
@ user907860:实际上,理想情况下,应该同时包含单个句子代码行。这句话将为像您这样的高级程序员简要地解释它,但是对于像我这样从未使用过另一种语言并且只懂Javascript的人,您对32位和二进制补码和big-endian的所有论述都很难理解。 。我是一名动手学习者,并且代码完全为我提供了帮助(尽管理所当然,它并不需要那么多的重复)。
Marcus Hughes

24

在JavaScript中,您可以使用双按位取反(~~n)代替Math.floor(n)(如果n为正数)或parseInt(n, 10)(即使n为负数)。n|n并且n&n总是产生与相同的结果~~n

var n = Math.PI;
n; // 3.141592653589793
Math.floor(n); // 3
parseInt(n, 10); // 3
~~n; // 3
n|n; // 3
n&n; // 3

// ~~n works as a replacement for parseInt() with negative numbers…
~~(-n); // -3
(-n)|(-n); // -3
(-n)&(-n); // -3
parseInt(-n, 10); // -3
// …although it doesn’t replace Math.floor() for negative numbers
Math.floor(-n); // -4

~计算一个按位求反()-(parseInt(n, 10) + 1),因此将返回两个按位求反-(-(parseInt(n, 10) + 1) + 1)

应该注意的是,在这三种选择中,n|n似乎是最快的

更新:此处提供更准确的基准测试:http : //jsperf.com/rounding-numbers-down

(如发布在最奇怪的语言功能上


1
n << 0;现在在V8上最快。n | 0;离我很近,这就是我用的
Bardi Harborow'Mar

@BardiHarborow,那又如何n >>> 0呢?
Pacerier '17

而不是如何使用它,一个更相关的问题可能是:“为什么要使用它?” 由此带来的潜在性能提升值得代码可读性吗?
瑞安

您能解释一下为什么每次使用按位运算符时都会将小数部分截断吗?按位运算符只对整数起作用吗?
船长

@Ryan代码的可读性很容易用两个斜杠后跟单词来纠正,例如wetMop = n|0; // bitwise version of Math.floor
Myndex

21

一个真实的 例子

^ 按位异或 I/O切换器

使用像value ^= 1会改变每一个呼叫value0, 1, 0, 1 ...

function toggle(evt) {
  evt.target.IO ^= 1;                                    // Bitwise XOR as 1/0 toggler
  evt.target.textContent = evt.target.IO ? "ON" : "OFF"; // Unleash your ideas
}

document.querySelectorAll("button").forEach( el =>
  el.addEventListener("click", toggle)
);
<button>OFF</button>
<button>OFF</button>
<button>OFF</button>


16

鉴于Java取得的进步(尤其是使用允许使用js进行服务器端编程的nodejs),JS中的代码越来越复杂。这是我使用按位运算符的几个实例:

  • IP地址操作:

    //computes the broadcast address based on the mask and a host address
    broadcast = (ip & mask) | (mask ^ 0xFFFFFFFF)
    
    
    //converts a number to an ip adress 
    sprintf(ip, "%i.%i.%i.%i", ((ip_int >> 24) & 0x000000FF),
                             ((ip_int >> 16) & 0x000000FF),
                             ((ip_int >>  8) & 0x000000FF),
                             ( ip_int        & 0x000000FF));
    

注意:这是C代码,但是JS几乎相同

  • CRC算法经常使用它们

在此查看维基百科条目

  • 屏幕分辨率操作

您是否有在这些情况下使用按位运算符的示例?
thomasrutter

我可以,但是我不能在开放源代码中工作,因此无法将您指向该代码。
Bogdan Gavril MSFT 2013年

14

判断数字是否为奇数:

function isOdd(number) {
    return !!(number & 1);
}

isOdd(1); // true, 1 is odd
isOdd(2); // false, 2 is not odd
isOdd(357); // true, 357 is odd

比模量更快-在性能真正重要的地方使用!


4
为什么不呢:function isOdd(number){return x%2; }
Duc Filan

1
性能。jsperf.com/modulo-vs-bitwise/8在大多数浏览器中,Bitwise速度更快(或者,是在发布答案时,在最近的Chrome浏览器中,tbf并没有太大区别
danwellman

11

很少有其他示例如何使用按位不和双按位不:

地板操作

~~2.5    // 2
~~2.1    // 2
~~(-2.5) // -2

检查indexOf是否返回-1

var foo = 'abc';
!~foo.indexOf('bar'); // true

10

您可以使用它们来翻转布尔值:

var foo = 1;
var bar = 0;
alert(foo ^= 1);
alert(bar ^= 1);

但是,这有点愚蠢,并且在大多数情况下,按位运算符在Javascript中没有很多应用程序。


8
那不是很傻。我一直用它来遍历图像,div等的“开” /“关”状态。

7
var arr = ['abc', 'xyz']

讨厌写

if (arr.indexOf('abc') > -1) {
  // 'abc' is in arr
}

if (arr.indexOf('def') === -1) {
  // 'def' is not in arr
}

检查数组中是否有东西?

您可以~像这样使用按位运算符:

if (~arr.indexOf('abc')) {
  // 'abc' is in arr
}

if (! ~arr.indexOf('def')) {
  // 'def' is not in arr
}

4
arr.includes自ES2016起也可以使用
Yann Bertrand,



2

我正在使用它们将三个数字展平为1,作为在Uint16Array中存储多维数组的一种方式。这是我正在开发的体素游戏的片段:

function Chunk() {
  this._blocks = new Uint16Array(32768);
  this._networkUpdates = [];
}

Chunk.prototype.getBlock = function(x, y, z) {
  return this._blocks[y + (x << 5) + (z << 10)];
};

Chunk.prototype.setBlock = function(x, y, z, value) {
  this._blocks[y + (x << 5) + (z << 10)] = value;
  this._networkUpdates.push(value + (y << 15) + (x << 20) + (z << 25));
};

Chunk.prototype.getUpdates = function() {
  return this._networkUpdates;
};

Chunk.prototype.processUpdate = function(update) {
  // this._blocks[Math.floor(update / 65536)] = update % 65536;
  this._blocks[update >> 16] = update & 65535;
};

var chunk = new Chunk();
chunk.setBlock(10, 5, 4);
alert(chunk.getBlock(10, 5, 4));
alert(chunk.getUpdates()[0]);


你能在这里解释一些鳕鱼吗?655355和10英寸的价值何在(x << 5) + (z << 10)
kevzettler 17-10-27

2

该答案包含对马克答案的解释。

通过阅读这些说明并运行代码片段,您可以获得一个想法。

var hex = 'ffaadd';
var rgb = parseInt(hex, 16); // rgb value is 16755421 in decimal = 111111111010101011011101 in binary = total 24 bits


var red   = (rgb >> 16) & 0xFF; // returns 255
var green = (rgb >> 8) & 0xFF;  // returns 170
var blue  = rgb & 0xFF;         // returns 221  

// HOW IS IT

// There are two bitwise operation as named SHIFTING and AND operations.
// SHIFTING is an operation the bits are shifted toward given direction by adding 0 (zero) bit for vacated bit fields.
// AND is an operation which is the same with multiplying in Math. For instance, if 9th bit of the given first bit-set is 0
// and 9th bit of the given second bit-set is 1, the new value will be 0 because of 0 x 1 = 0 in math.

// 0xFF (000000000000000011111111 in binary) - used for to evaluate only last 8 bits of a given another bit-set by performing bitwise AND (&) operation. 
// The count of bits is 24 and the first 16 bits of 0xFF value consist of zero (0) value. Rest of bit-set consists of one (1) value.
console.log("0xFF \t\t\t\t: ", 0xFF) 


// 111111111010101011011101 -> bits of rgb variable
// 000000000000000011111111 -> 255 after (rgb >> 16) shifting operation
// 000000000000000011111111 -> 255 complement (changes the first 16 bits and does nothing for the last 8 bits)
// 000000000000000011111111 -> result bits after performing bitwise & operation
console.log("Red - (rgb >> 16) & 0xFF \t: ", (rgb >> 16) & 0xFF) // used for to evaluate the first 8 bits

// 111111111010101011011101 -> bits of rgb variable
// 000000001111111110101010 -> 65450 -> 'ffaa'
// 000000000000000011111111 -> 255 complement (changes the first 16 bits and does nothing for the last 8 bits)
// 000000000000000010101010 -> result bits after performing bitwise & operation
// calculation -> 000000001111111110101010 & 000000000000000011111111 = 000000000000000010101010 = 170 in decimal = 'aa' in hex-decimal
console.log("Green - (rgb >> 8) & 0xFF \t: ", (rgb >> 8) & 0xFF) // used for to evaluate the middle 8 bits 

// 111111111010101011011101 -> 'ffaadd'
// 000000000000000011111111 -> 255 complement (changes the first 16 bits and does nothing for the last 8 bits)
// 000000000000000011011101 -> result bits after performing bitwise & operation 
// calculation -> 111111111010101011011101 & 000000000000000011111111 = 221 in decimal = 'dd' in hex-decimal
console.log("Blue - rgb & 0xFF \t\t: ", rgb & 0xFF) // // used for to evaluate the last 8 bits.

console.log("It means that `FFAADD` hex-decimal value specifies the same color with rgb(255, 170, 221)")

/* console.log(red)
console.log(green)
console.log(blue) */


0

当您使用十六进制值和位时,它们似乎非常有用。由于4位可以表示0到F。

1111 = F 1111 1111 = FF。


0

使用Node.js的示例

假设您有一个包含这些内容的文件(称为multiple.js),则可以运行

`node multiply <number> <number>`

并获得与在相同的两个数字上使用乘法运算符一致的输出。Mulitply函数中进行的位移位是如何获取代表一个数字的位掩码并使用它来翻转另一个数字的位以进行快速操作的示例。

var a, b, input = process.argv.slice(2);

var printUsage = function() {
  console.log('USAGE:');
  console.log('  node multiply <number> <number>');
}

if(input[0] === '--help') {+
  printUsage();
  process.exit(0);
}

if(input.length !== 2) {
  printUsage();
  process.exit(9);
}

if(isNaN(+input[0]) || isNaN(+input[1])) {
  printUsage();
  process.exit(9);
}

// Okay, safe to proceed

a = parseInt(input[0]),
b = parseInt(input[1]);

var Multiply = function(a,b) {
  var x = a, y = b, z = 0;

  while( x > 0 ) {
    if(x % 2 === 1) {
      z = z + y;
    }
    y = y << 1;
    x = x >> 1;
  }

  return z;
}

var result = Multiply(a,b);

console.log(result);

-1

我只是发现这个问题试图确认按位运算AND符是否也在&Javascript中。

由于您要求一个示例:

if ($('input[id="user[privileges]"]').length > 0) {
    $('#privileges button').each(function () {
        if (parseInt($('input[id="user[privileges]"]').val()) & parseInt($(this).attr('value'))) {
            $(this).button('toggle');
        }
    });
}

给定一个隐藏字段的位掩码值,它将使用jQuery填充按钮的状态:

  • none = 0
  • user = 1
  • administrator = 2
  • user+ administrator=3
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.