J'ai lu "quels sont les opérateurs de bitwise?" , je sais donc ce queopérateurs au niveau du bit sont mais je ne comprends toujours pas comment les utiliser. Quelqu'un peut-il offrir des exemples concrets de situations dans lesquelles un opérateur bitwise serait utile en JavaScript?
Merci.
En fouillant simplement dans la source jQuery, j'ai trouvé quelques endroits où les opérateurs au niveau du bit sont utilisés, par exemple: (uniquement l'opérateur &)
// 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;
Exemple:
Analyse la valeur hexadécimale pour obtenir les valeurs de couleur RVB.
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
I utilise fortement des opérateurs au niveau du bit pour les conversions numériques dans les scripts de production, car ils sont parfois beaucoup plus rapides que leurs équivalents Math
ou parseInt
.
Le prix que je dois payer est lisibilité du code. Donc j’utilise habituellement Math
en développement et au niveau du bit en production.
Vous pouvez trouver quelques astuces de performance sur jsperf.com .
Comme vous pouvez le constater, les navigateurs n'optimisent pas Math.ceil
et parseInt
pendant des années, aussi je prédis que bitwise sera un moyen plus rapide et plus rapide de faire des choses également dans l'avenir .
Quelques lectures supplémentaires sur SO ...
Bonus: cheat sheet pour | 0
: un moyen facile et rapide de convertir n'importe quoi en entier:
( 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;
et de la magie pour moi:
3 | '0px' === 3;
En JavaScript, vous pouvez utiliser une double négation binaire (~~n
) pour remplacer Math.floor(n)
(si n
est un nombre positif) ou parseInt(n, 10)
(même si n
est négatif). n|n
et n&n
donnent toujours les mêmes résultats que ~~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
Une seule négation au niveau du bit (~
) calcule -(parseInt(n, 10) + 1)
; deux négations au niveau du bit renverront donc -(-(parseInt(n, 10) + 1) + 1)
.
Il convient de noter que parmi ces trois alternatives, n|n
semble être le plus rapide.
Mise à jour: Des repères plus précis ici: http://jsperf.com/rounding-numbers-down
(Telle que publiée sur Fonction de langue la plus étrange )
Une vraie vieexemple :
^
bitwise XOR en tant que I/O
basculeUtilisé comme value ^= 1
changera à chaque appel la value
en 0, 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>
Compte tenu des progrès réalisés par Javascript (en particulier avec nodejs qui permet la programmation côté serveur avec js), le code dans JS est de plus en plus complexe. Voici quelques cas où j'ai utilisé des opérateurs au niveau des bits:
Opérations d'adresse 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));
Note: c'est du code C, mais JS est presque identique
Découvrez l'entrée de wikipedia sur ce
Pour dire si un nombre est impair:
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
Plus rapide que le module - utilisez où performance vraiment compte!
Quelques autres exemples d'utilisation pas à pas et à double pas:
Fonctionnement au sol
~~2.5 // 2
~~2.1 // 2
~~(-2.5) // -2
Vérifie si indexOf a retourné -1 ou non
var foo = 'abc';
!~foo.indexOf('bar'); // true
Vous pouvez les utiliser pour renverser une valeur booléenne:
var foo = 1;
var bar = 0;
alert(foo ^= 1);
alert(bar ^= 1);
C'est un peu idiot et pour la plupart des opérateurs au niveau des bits n'ont pas beaucoup d'applications en Javascript.
var arr = ['abc', 'xyz']
Agacé d'écrire
if (arr.indexOf('abc') > -1) {
// 'abc' is in arr
}
if (arr.indexOf('def') === -1) {
// 'def' is not in arr
}
vérifier si quelque chose est à l'intérieur d'un tableau?
Vous pouvez utiliser l'opérateur binaire ~
comme suit:
if (~arr.indexOf('abc')) {
// 'abc' is in arr
}
if (! ~arr.indexOf('def')) {
// 'def' is not in arr
}
Utilisé intensivement, par exemple, dans les événements JS.
Je l'ai utilisé une fois pour un widget permissions . Les autorisations de fichiers sous Unix sont un masque de bits. Par conséquent, pour les analyser, vous devez utiliser des opérations sur les bits.
Je les utilise pour aplatir trois nombres en 1 afin de stocker des tableaux multidimensionnels dans un Uint16Array . Voici un extrait du jeu Voxel que je développe:
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]);
Cette réponse contient des explications sur La réponse de Mark .
En lisant ces explications et en lançant l'extrait de code, une idée peut être gagnée.
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) */
Ils semblent être très utiles lorsque vous travaillez avec des valeurs hexadécimales et des bits. Depuis 4 bits peuvent représenter 0 à F.
1111 = F 1111 1111 = FF.
Exemple d'utilisation de Node.js
En supposant que vous ayez un fichier (appelé multiply.js) avec ce contenu, vous pouvez exécuter
`node multiply <number> <number>`
et obtenez une sortie compatible avec l'utilisation de l'opérateur de multiplication sur les deux mêmes nombres. Le décalage de bits dans la fonction Mulitply
est un exemple de la manière de prendre le masque de bits représentant un nombre et de l'utiliser pour retourner des bits d'un autre nombre pour des opérations rapides.
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);