Wo würde ich einen bitweisen Operator in JavaScript verwenden?


72

Ich habe gelesen , was sind bitweise Operatoren? Ich weiß also, was bitweise Operatoren sind, aber ich bin mir immer noch nicht sicher , wie man sie verwenden könnte. Kann jemand Beispiele aus der Praxis anbieten, wo ein bitweiser Operator in JavaScript nützlich wäre?

Vielen Dank.

Bearbeiten:

Beim Durchsuchen der jQuery-Quelle habe ich einige Stellen gefunden, an denen bitweise Operatoren verwendet werden, zum Beispiel: (nur der Operator &)

// 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;

Antworten:


71

Beispiel:

Analysiert den Hexadezimalwert, um RGB-Farbwerte zu erhalten.

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  

Wie entspricht dies UTF-16?
Sebastian Barth

6
@SebastianBarth wie geht das nicht? Es gibt keinen Teil dieses Codes, in dem die Zeichenkodierung auch nur aus der Ferne relevant ist.
Hobbs

45

Ich stark verwenden Bitoperatoren für numerische convertions in Produktion Skripte, denn manchmal sind sie viel schneller als ihre Mathoder parseIntÄquivalente.

Der Preis, den ich zahlen muss, ist die Lesbarkeit des Codes . Also benutze ich normalerweise Mathin der Entwicklung und bitweise in der Produktion.

Auf jsperf.com finden Sie einige Performance-Tricks .

Wie Sie sehen können, optimieren Browser nicht Math.ceilund parseIntseit Jahren, daher gehe ich davon aus, dass bitweise auch schneller und kürzer sein wird, um Dinge in Zukunft zu erledigen .

Einige weiterführende Literatur zu SO ...


Bonus: Spickzettel für | 0: eine einfache und schnelle Möglichkeit, etwas in eine Ganzzahl umzuwandeln:

( 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;

und etwas Magie für mich:

3 | '0px' === 3;

oder verwenden Sie den Closure Compiler im erweiterten Modus, der all diese Optimierungen für Sie
Pawel,

2
Das ist keine gute Antwort. Auf den ersten Blick sieht es aus wie eine Referenz und mit vielen Informationen (ich habe sie gestern sogar positiv bewertet), aber nach einer genaueren Betrachtung stellt sich heraus, dass dies nicht wahr ist.
user907860

4
Alle diese 20 Zeilen oder so von Beispielen könnten in einem einzigen Satz ausgedrückt worden sein: Die bitweisen Operatoren arbeiten mit 32-Bit-Zweierkomplement-Big-Endian-Darstellungen (kurz 32-Bit) von Zahlen, sodass jeder ihrer Operanden konvertiert wird in dieses Format gemäß den folgenden Regeln: Eine Zahl wird vom 64-Bit-Format IEEE-754 in 32-Bit konvertiert, und alles andere wird zuerst in eine Zahl konvertiert, wie in der ECMAScript-Spezifikation angegeben (nämlich für Objekte (dh Objekte) , Arrays, Funktionen) über einen Aufruf seiner valueOf-Methode) und dann wird diese Nummer in das 32-Bit-Format konvertiert
user907860

1
Sie können dies versuchen: 'use strict'; Function.prototype.valueOf = function() {return 2;};console.log(( (function(){})|0 ) === 0);und Sie werden sehen, dass Ihre letzten beiden Beispiele nicht korrekt sind und so weiter.
user907860

2
@ user907860: Eigentlich sollten im Idealfall sowohl der einzelne Satz als auch die Codezeilen vorhanden sein. Der Satz wird es für fortgeschrittenere Programmierer wie Sie kurz und bündig erklären, aber für Leute wie mich, die noch nie mit einer anderen Sprache gearbeitet haben und nur Javascript kennen, sind alle Ihre Gespräche über 32-Bit- und Zweierkomplement und Big-Endian schwer zu verstehen . Ich bin ein Hands-on - Lernende , und der Code half mir ganz (obwohl gewährt, es nicht ganz brauchen , dass viele Wiederholungen).
Marcus Hughes

24

In JavaScript können Sie eine doppelte bitweise Negation ( ~~n) als Ersatz für Math.floor(n)(wenn neine positive Zahl ist) oder parseInt(n, 10)(auch wenn sie nnegativ ist) verwenden. n|nund n&nliefern immer die gleichen Ergebnisse wie ~~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

Eine einzelne bitweise Negation ( ~) wird berechnet -(parseInt(n, 10) + 1), sodass zwei bitweise Negationen zurückgegeben werden -(-(parseInt(n, 10) + 1) + 1).

Es ist anzumerken, dass von diesen drei Alternativen n|ndie schnellste zu sein scheint .

Update: Genauere Benchmarks hier: http://jsperf.com/rounding-numbers-down

(Wie auf Strangest Language Feature veröffentlicht )


1
n << 0;ist jetzt am schnellsten auf V8. n | 0;ist sehr dicht dahinter und ist was ich benutze.
Bardi Harborow

@BardiHarborow, was ist mit n >>> 0?
Pacerier

Anstatt wie Sie es verwenden können, könnte eine sachdienlichere Frage lauten: "Warum sollten Sie es verwenden?" Sind potenzielle Leistungssteigerungen die Lesbarkeit des Codes wert?
Ryan

Können Sie erklären, warum die Dezimalstelle jedes Mal abgeschnitten wird, wenn Sie einen bitweisen Operator verwenden? Arbeiten bitweise Operatoren nur mit ganzen Zahlen?
Captainlonate

Die Lesbarkeit des @ Ryan-Codes kann leicht mit zwei Schrägstrichen gefolgt von Wörtern korrigiert werden, z. B.wetMop = n|0; // bitwise version of Math.floor
Myndex,

21

Ein Beispiel aus dem wirklichen Leben :

^bitweises XOR als I/OTogler

Wird wie verwendet value ^= 1, ändert sich bei jedem Aufruf des valueto0, 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

Angesichts der Fortschritte, die Javascript macht (insbesondere bei NodeJS, die eine serverseitige Programmierung mit Js ermöglichen), gibt es in JS immer komplexeren Code. Hier sind einige Fälle, in denen ich bitweise Operatoren verwendet habe:

  • IP-Adressoperationen:

    //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));
    

Hinweis: Dies ist C-Code, aber JS ist fast identisch

  • CRC-Algorithmen verwenden sie häufig

Schauen Sie sich dazu den Wikipedia-Eintrag an

  • Bildschirmauflösungsoperationen

Haben Sie Beispiele dafür, wie Sie in diesen Situationen bitweise Operatoren verwendet haben?
Thomasrutter

Das tue ich, aber ich arbeite nicht in Open Source, daher kann ich Sie nicht auf den Code verweisen.
Bogdan Gavril MSFT

14

Um festzustellen, ob eine Zahl ungerade ist:

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

Schneller als Modul - dort einsetzen, wo Leistung wirklich zählt!


4
Warum nicht: Funktion isOdd (Zahl) {return x% 2; }
Duc Filan

1
Performance. jsperf.com/modulo-vs-bitwise/8 Bitwise ist in den meisten Browsern schneller (oder, es war zum Zeitpunkt der Veröffentlichung der Antwort, in den letzten Chrome gibt es keinen großen Unterschied tbf
danwellman

11

Einige andere Beispiele für die Verwendung von bitweise nicht und doppelt bitweise nicht:

Bodenbetrieb

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

Überprüfen Sie, ob indexOf -1 zurückgegeben hat oder nicht

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

10

Sie können sie zum Umdrehen eines Booleschen Werts verwenden:

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

Dies ist allerdings etwas albern und zum größten Teil haben bitweise Operatoren nicht viele Anwendungen in Javascript.


8
Das ist nicht albern. Ich benutze das, um ständig durch "Ein" / "Aus" -Zustände für Bilder, Divs usw. zu blättern.
Crescent Fresh

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

Verärgert zu schreiben

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

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

um zu überprüfen, ob sich etwas in einem Array befindet?

Sie können den bitweisen Operator folgendermaßen verwenden ~:

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

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

4
arr.includeskann auch seit ES2016
Yann Bertrand



2

Ich verwende sie, um drei Zahlen zu 1 zu reduzieren, um mehrdimensionale Arrays in einem Uint16Array zu speichern . Hier ist ein Ausschnitt aus einem Voxel-Spiel, das ich entwickle:

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]);


Könntest du hier etwas vom Kabeljau erklären? Was ist der 65535Wert, warum die 5 und 10 in(x << 5) + (z << 10)
kevzettler

2

Diese Antwort enthält Erklärungen zu Marks Antwort .

Durch Lesen dieser Erklärungen und Ausführen des Code-Snippets kann eine Idee gewonnen werden.

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

Sie scheinen sehr nützlich zu sein, wenn Sie mit Hex-Werten und Bits arbeiten. Da 4 Bits 0 bis F darstellen können.

1111 = F 1111 1111 = FF.


0

Beispiel mit Node.js

Angenommen, Sie hätten eine Datei (multiply.js) mit diesen Inhalten, könnten Sie ausführen

`node multiply <number> <number>`

und eine Ausgabe erhalten, die mit der Verwendung des Multiplikationsoperators für dieselben zwei Zahlen übereinstimmt. Die in der MulitplyFunktion ablaufende Bitverschiebung ist ein Beispiel dafür, wie die Bitmaske, die eine Zahl darstellt, verwendet wird, um Bits in einer anderen Zahl für schnelle Operationen umzudrehen.

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

Ich habe gerade diese Frage gefunden, um zu bestätigen, ob der bitweise ANDOperator auch &in Javascript ist.

Da Sie nach einem Beispiel gefragt haben:

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');
        }
    });
}

Es füllt den Status von Schaltflächen mit jQuery, wenn ein Bitmaskenwert eines ausgeblendeten Felds angegeben wird:

  • none = 0
  • user = 1
  • administrator = 2
  • user+ administrator=3
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.