164 votes

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

Je regardais le code de Mozilla qui ajoute 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 ?

231voto

bobince Points 270740

Il ne se contente pas de convertir les non-nombres en nombres, il les convertit en nombres qui peuvent être exprimés sous forme d'ints non signés 32 bits.

Bien que les nombres de JavaScript soient des nombres flottants en double précision (*), les opérateurs bit à bit ( << , >> , & , | y ~ ) sont définis en termes d'opérations sur des entiers de 32 bits. Une opération par bit convertit le nombre en un nombre entier signé de 32 bits, en perdant toutes les fractions et les bits supérieurs à 32, avant d'effectuer le calcul et de le reconvertir en nombre.

Donc, faire une opération par bit sans effet réel, comme un décalage vers la droite de 0 bits >>0 est un moyen rapide d'arrondir un nombre et de s'assurer qu'il se situe dans la plage des int 32 bits. En outre, le triple >>> Après avoir effectué son opération non signée, l'opérateur convertit les résultats de son calcul en Nombre sous la forme d'un nombre entier non signé plutôt que sous la forme d'un nombre entier signé comme le font les autres opérateurs. Il peut donc être utilisé pour convertir les négatifs en la version 32 bits à deux compléments sous la forme d'un grand Nombre. Utilisation de >>>0 s'assure que vous avez un nombre entier entre 0 et 0xFFFFFFFF.

Dans ce cas, c'est utile car l'ECMAScript définit les index des tableaux en termes d'ints non signés de 32 bits. Donc, si vous essayez d'implémenter array.filter de manière à reproduire exactement ce que dit la norme ECMAScript Fifth Edition, vous devez convertir le nombre en un int non signé de 32 bits comme ceci.

(En réalité, cela n'est guère nécessaire dans la mesure où, avec un peu de chance, les gens ne vont pas mettre en place un système d'alarme). array.length a 0.5 , -1 , 1e21 o 'LEMONS' . Mais c'est d'auteurs JavaScript dont nous parlons, alors on ne sait jamais...)

Résumé :

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

(* : en fait, ils sont définis comme se comportant comme des flottants. Je ne serais pas surpris qu'un moteur JavaScript utilise les ints quand il le peut, pour des raisons de performances. Mais ce serait un détail d'implémentation dont vous ne pourriez tirer aucun avantage).

2 votes

+2 dans la description approfondie et le tableau, -1 parce que array.length se valide lui-même et ne peut pas être arbitrairement fixé à quelque chose qui n'est pas un entier ou 0 (FF jette cette erreur : RangeError: invalid array length ).

4 votes

Toutefois, la spécification autorise délibérément l'appel de nombreuses fonctions Array sur des fonctions non Array (par exemple, par l'intermédiaire de la fonction Array.prototype.filter.call ), donc array pourrait ne pas être un vrai Array Il peut s'agir d'une autre classe définie par l'utilisateur. (Malheureusement, il ne peut pas s'agir d'une NodeList, ce qui est le cas lorsque vous voulez vraiment le faire, car c'est un objet hôte. Le seul endroit où l'on peut faire cela de manière réaliste est donc l'objet arguments pseudo-rayon).

0 votes

Excellente explication et excellents exemples ! Malheureusement, c'est un autre aspect insensé de Javascript. Je ne comprends pas ce qu'il y a de si horrible à lancer une erreur lorsque vous recevez le mauvais type. Il est possible d'autoriser le typage dynamique sans permettre à chaque erreur accidentelle de créer un casting de type. :(

34voto

driis Points 70872

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

0 votes

Ivan, cela la décalerait de 0 place ; cette déclaration ne changerait rien.

3 votes

@Ivan, normalement, je dirais que décaler une valeur de zéro place n'a absolument aucun sens. Mais c'est du Javascript, donc il pourrait y avoir un sens derrière cela. Je ne suis pas un gourou du Javascript, mais il pourrait s'agir d'un moyen de s'assurer que la valeur est en fait un nombre entier dans le langage sans typage Javasacript.

2 votes

@Ivan, voir la réponse de Justin ci-dessous. Il s'agit en fait d'un moyen de s'assurer que la variable len contient un nombre.

29voto

Justin Johnson Points 16243

Driis a suffisamment expliqué ce qu'est l'opérateur et ce qu'il fait. Voici la signification de cet opérateur et la raison pour laquelle il a été utilisé :

Déplacement de toute direction en 0 retourne le nombre original et lancera null a 0 . Il semble que l'exemple de code que vous regardez utilise la fonction this.length >>> 0 afin de garantir que len est numérique même si this.length n'est pas défini.

Pour de nombreuses personnes, les opérations par bit ne sont pas claires (et Douglas Crockford/jslint suggère de ne pas utiliser de telles choses). Cela ne veut pas dire que c'est mal de le faire, mais des méthodes plus favorables et plus familières existent pour rendre le code plus lisible. Une façon plus claire de s'assurer que len es 0 est l'une des deux méthodes suivantes.

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

o

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

1 votes

Bien que votre deuxième solution puisse parfois être évaluée à NaN .. Par exemple. +{} ... C'est probablement mieux de combiner les deux : +length||0

1 votes

This.length est dans le contexte de l'objet array, qui ne peut être autre chose qu'un entier non négatif (au moins dans FF), donc ce n'est pas une possibilité ici. De plus, {} || 1 renvoie {} donc vous n'êtes pas mieux loti si this.length est un objet. L'avantage du casting unaire de this.length dans la première méthode est qu'il gère les cas où this.length est NaN. J'ai modifié la réponse pour refléter cela.

0 votes

Jslint se plaindrait aussi de var len = +this.length en tant que "confusing pluss". Douglas, tu es si pointilleux !

0voto

nitinsridar Points 213

L'exemple de code Java ci-dessous l'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));

Le résultat est le suivant :

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X