web-dev-qa-db-fra.com

Qu'est-ce que l'opérateur JavaScript >>> et comment l'utilisez-vous?

Je cherchais du code de Mozilla qui ajoutait une méthode de filtrage à Array et il y avait une ligne de code qui m'a dérouté.

var len = this.length >>> 0;

Je n'ai jamais vu >>> utilisé en JavaScript auparavant.
Qu'est-ce que c'est et que fait-il?

138
Kenneth J

Il ne convertit pas seulement des non-nombres en nombre, il les convertit en nombres qui peuvent être exprimés en entiers non signés 32 bits.

Bien que les numéros JavaScript soient des flottants double précision (*), les opérateurs au niveau du bit (<<, >>, &, | Et ~ ) sont définis en termes d'opérations sur des entiers 32 bits. Faire une opération au niveau du bit convertit le nombre en un entier signé 32 bits, perdant toutes les fractions et les bits supérieurs à 32, avant de faire le calcul, puis de reconvertir en nombre.

Ainsi, effectuer une opération au niveau du bit sans effet réel, comme un décalage vers la droite de 0 bit >>0, Est un moyen rapide d'arrondir un nombre et de s'assurer qu'il se trouve dans la plage int de 32 bits. De plus, l'opérateur triple >>>, Après avoir effectué son opération non signée, convertit les résultats de son calcul en nombre sous la forme d'un entier non signé plutôt que l'entier signé que les autres effectuent, de sorte qu'il peut être utilisé pour convertir des négatifs en 32 -bit-two's complément version comme un grand nombre. L'utilisation de >>>0 Garantit que vous avez un entier compris entre 0 et 0xFFFFFFFF.

Dans ce cas, cela est utile car ECMAScript définit les index de tableau en termes d'entiers non signés 32 bits. Donc, si vous essayez d'implémenter array.filter D'une manière qui reproduit exactement ce que dit la norme ECMAScript Fifth Edition, vous devez convertir le nombre en entier non signé 32 bits comme celui-ci.

(En réalité, il n'y a pas grand besoin pratique de cela car, espérons-le, les gens ne définiront pas array.length Sur 0.5, -1, 1e21 Ou 'LEMONS'. Mais ce sont les auteurs JavaScript dont nous parlons, donc on ne sait jamais ...)

Sommaire:

1>>>0            === 1
-1>>>0           === 0xFFFFFFFF          -1>>0    === -1
1.7>>>0          === 1
0x100000002>>>0  === 2
1e21>>>0         === 0xDEA00000          1e21>>0  === -0x21600000
Infinity>>>0     === 0
NaN>>>0          === 0
null>>>0         === 0
'1'>>>0          === 1
'x'>>>0          === 0
Object>>>0       === 0

(*: eh bien, ils sont définis comme se comportant comme des flottants. Cela ne me surprendrait pas si un moteur JavaScript utilisait réellement des ints quand il le pouvait, pour des raisons de performances. Mais ce serait un détail d'implémentation que vous n'auriez pas à prendre avantage de.)

192
bobince

L'opérateur de décalage à droite non signé est utilisé dans toutes les implémentations de la méthode array extra's de Mozilla, pour garantir que la propriété length est un entier 32 bits non signé.

La propriété length des objets tableau est décrite dans la spécification comme:

Chaque objet Array a une propriété length dont la valeur est toujours un entier non négatif inférieur à 232.

Cet opérateur est le moyen le plus court pour y parvenir, les méthodes de tableau en interne utilisent le ToUint32 opération, mais cette méthode n'est pas accessible et existe sur la spécification à des fins d'implémentation.

Les implémentations Mozilla array extras essaient d'être ECMAScript 5 conformes, regardez la description de Array.prototype.indexOf méthode (§ 15.4.4.14):

1. Soit O le résultat de l'appel de ToObject en passant l'argument cette valeur 
. 
 2. Soit lenValue le résultat de l'appel de la méthode interne [[Get]] de O avec 
 L'argument "length". 
 3. Soit len ​​ ToUint32 (lenValue) . 
 .... 

Comme vous pouvez le voir, ils veulent juste reproduire le comportement du ToUint32 méthode pour se conformer à la spécification ES5 sur une implémentation ES3, et comme je l'ai déjà dit, opérateur de décalage vers la droite non signé est le moyen le plus simple.

56
CMS

C'est l'opérateur décalage de bit à droite non signé . La différence entre ceci et opérateur de décalage de bit à droite signé , est que ( opérateur de décalage de bit à droite non signé (- === -) ( >>> ) remplit de zéros à partir de la gauche, et l'opérateur de décalage de droite signé à droite ( >> ) se remplit du bit de signe, préservant ainsi le signe de la valeur numérique lorsqu'il est décalé.

30
driis

Driis a suffisamment expliqué ce qu'est l'opérateur et ce qu'il fait. Voici le sens derrière cela/pourquoi il a été utilisé:

Décaler une direction de 0 ne renvoie le numéro d'origine et convertira null en 0. Il semble que l'exemple de code que vous regardez utilise this.length >>> 0 pour garantir que len est numérique même si this.length n'est pas défini.

Pour de nombreuses personnes, les opérations au niveau du bit ne sont pas claires (et Douglas Crockford/jslint suggère de ne pas utiliser de telles choses). Cela ne signifie pas que c'est mal à faire, mais il existe des méthodes plus favorables et familières pour rendre le code plus lisible. Un moyen plus clair de s'assurer que len est 0 est l'une des deux méthodes suivantes.

// Cast this.length to a number
var len = +this.length;

ou

// Cast this.length to a number, or use 0 if this.length is
// NaN/undefined (evaluates to false)
var len = +this.length || 0; 
28
Justin Johnson

>>> est l'opérateur non signé décalage à droite ( voir p. 76 de la spécification JavaScript 1.5 ), contrairement à >>, l'opérateur de décalage vers la droite signé.

>>> modifie les résultats du décalage des nombres négatifs car il ne conserve pas le bit de signe lors du décalage . Les conséquences de cela peuvent être comprises par exemple, à partir d'un interprète:

$ 1 >> 0
1
$ 0 >> 0
0
$ -1 >> 0
-1
$ 1 >>> 0
1
$ 0 >>> 0
0
$ -1 >>> 0
4294967295
$(-1 >>> 0).toString(16)
"ffffffff"
$ "cabbage" >>> 0
0

Donc, ce qui est probablement destiné à être fait ici, c'est d'obtenir la longueur, ou 0 si la longueur n'est pas définie ou n'est pas un entier, selon le "cabbage" exemple ci-dessus. Je pense que dans ce cas, il est sûr de supposer que this.length ne sera jamais < 0. Néanmoins, je dirais que cet exemple est un hack méchant , pour deux raisons:

  1. Le comportement de <<< lors de l'utilisation de nombres négatifs, un effet secondaire probablement non prévu (ou susceptible de se produire) dans l'exemple ci-dessus.

  2. L'intention du code n'est pas évidente , comme le vérifie l'existence de cette question.

La meilleure pratique consiste probablement à utiliser quelque chose de plus lisible à moins que les performances ne soient absolument critiques:

isNaN(parseInt(foo)) ? 0 : parseInt(foo)
15
fmark

Deux raisons:

  1. Le résultat de >>> est une "intégrale"

  2. undefined >>> 0 = 0 (puisque JS tentera de contraindre le LFS au contexte numérique, cela fonctionnera également pour "foo" >>> 0, etc.)

N'oubliez pas que les nombres dans JS ont une représentation interne de double. C'est juste un moyen "rapide" de raison de base pour la longueur.

Cependant , -1 >>> 0 (oups, probablement pas une longueur souhaitée!)

10
user166390

Exemple Java Le code ci-dessous explique bien:

int x = 64;

System.out.println("x >>> 3 = "  + (x >>> 3));
System.out.println("x >> 3 = "  + (x >> 3));
System.out.println(Integer.toBinaryString(x >>> 3));
System.out.println(Integer.toBinaryString(x >> 3));

La sortie est la suivante:

x >>> 3 = 536870904
x >> 3 = -8
11111111111111111111111111000
11111111111111111111111111111000
0
nitinsridar