Je regardais du code de Mozilla qui ajoutait une méthode de filtrage à Array et il y avait une ligne de code qui me déroutait.
var len = this.length >>> 0;
Je n'ai jamais vu >>> utilisé en JavaScript auparavant.
Qu'est-ce que c'est et que fait-il?
javascript
operators
bit-shift
Kenneth J
la source
la source
Array.prototype.push
/Array.prototype.pop
- hexmen.com/blog/2006/12/push-and-pop (bien qu'il ait fait les tests, haha).Réponses:
Il ne convertit pas seulement les non-nombres en nombres, il les convertit en nombres qui peuvent être exprimés sous forme d'entiers non signés 32 bits.
Bien que les chiffres de JavaScript sont flotteurs double précision (*), les opérateurs binaires (
<<
,>>
,&
,|
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 de rang supérieur à 32, avant de faire le calcul, puis de revenir en nombre.Donc, faire une opération au niveau du 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 est dans la plage int 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 comme un entier non signé plutôt que l'entier signé que font les autres, de sorte qu'il peut être utilisé pour convertir les négatifs en complément à deux de 32 bits. version comme un grand nombre. L'utilisation>>>0
garantit que vous avez un entier compris entre 0 et 0xFFFFFFFF.Dans ce cas, cela est utile car ECMAScript définit les index Array en termes d'entiers non signés 32 bits. Donc, si vous essayez d'implémenter
array.filter
d'une manière qui duplique exactement ce que dit la norme ECMAScript Fifth Edition, vous convertiriez le nombre en int 32 bits non signé comme ceci.(En réalité , il y a peu de besoin pratique de ce que nous espérons les gens ne vont pas être mise
array.length
à0.5
,-1
,1e21
ou'LEMONS'
. Mais ce sont des auteurs JavaScript dont nous parlons, vous ne savez jamais ...)Résumé:
(*: eh bien, ils sont définis comme se comportant comme des flottants. Cela ne me surprendrait pas si un moteur JavaScript utilisait réellement 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.)
la source
RangeError: invalid array length
.Array.prototype.filter.call
), doncarray
peut-être pas réellement un vraiArray
: il peut s'agir d'une autre classe définie par l'utilisateur. (Malheureusement, il ne peut pas être fiable de NodeList, c'est à ce moment-là que vous voulez vraiment faire cela, car c'est un objet hôte. Cela laisse le seul endroit où vous le feriez de manière réaliste en tant quearguments
pseudo-Array.)if
ressemblerait l' énoncé pour cela lorsque vous essayez d'identifier que le côté gauche de l'évaluation n'était pas un int?'lemons'>>>0 === 0 && 0 >>>0 === 0
évalue comme vrai? même si les citrons est évidemment un mot ..?L'opérateur de décalage vers la droite non signé est utilisé dans toutes les implémentations de méthode du tableau extra de Mozilla, pour garantir que la
length
propriété est un entier 32 bits non signé .La
length
propriété des objets de tableau est décrite dans la spécification comme:Cet opérateur est le moyen le plus court pour y parvenir, les méthodes de tableau en interne utilisent l'
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 de Mozilla array extras essaient d'être compatibles ECMAScript 5 , regardez la description de la
Array.prototype.indexOf
méthode (§ 15.4.4.14):Comme vous pouvez le voir, ils veulent juste reproduire le comportement de la
ToUint32
méthode pour se conformer à la spécification ES5 sur une implémentation ES3, et comme je l'ai déjà dit, l' opérateur de décalage droit non signé est le moyen le plus simple.la source
ToUint32
me semble un peu inutile.Array.prototype
méthodes sont intentionnellement génériques , elles peuvent être utilisées sur des objets de type tableau , par exempleArray.prototype.indexOf.call({0:'foo', 1:'bar', length: 2}, 'bar') == 1;
. L'arguments
objet est également un bon exemple. Pour les objets tableau purs , il est impossible de changer le type de lalength
propriété, car ils implémentent une méthode interne spéciale [[Put
]], et lorsqu'une affectation est faite à lalength
propriété, elle est à nouveau convertieToUint32
et d'autres actions sont entreprises, comme la suppression des index ci-dessus la nouvelle longueur ...C'est l' opérateur de décalage de bit droit non signé . La différence entre cela et l' opérateur de décalage de bit droit signé est que l' opérateur de décalage de bit droit non signé ( >>> ) se remplit de zéros à partir de la gauche, et l' opérateur de décalage de bit droit signé ( >> ) se remplit du bit de signe, donc en préservant le signe de la valeur numérique lorsqu'elle est décalée.
la source
>>>
convertit en un entier, ce+
que ne fait pas unaire .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é:
Le passage par une direction
0
ne renvoie le nombre initial et jeténull
à0
. Il semble que l'exemple de code que vous regardez utilisethis.length >>> 0
pour s'assurer qu'illen
est numérique même s'ilthis.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 des méthodes plus favorables et familières existent pour rendre le code plus lisible. Une façon de faire en sorte que plus clair
len
est0
est l' une des deux méthodes suivantes.ou
la source
NaN
.. Par exemple+{}
... Il est probablement préférable de combiner les deux:+length||0
>>>
est le unsigned opérateur de décalage à droite ( voir p. 76 de la spécification JavaScript 1.5 ), par opposition au>>
, la signature opérateur de décalage vers la droite.>>>
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 ceci peuvent être comprises par exemple, à partir d'un interprète:Donc, ce qui est probablement destiné à être fait ici est d'obtenir la longueur, ou 0 si la longueur n'est pas définie ou n'est pas un entier, comme dans l'
"cabbage"
exemple ci-dessus. Je pense que dans ce cas, il est prudent de supposer quethis.length
cela ne le sera jamais< 0
. Néanmoins, je dirais que cet exemple est un mauvais hack , pour deux raisons:Le comportement de
<<<
lors de l'utilisation de nombres négatifs, un effet secondaire probablement pas prévu (ou susceptible de se produire) dans l'exemple ci-dessus.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 essentielles:
la source
-1 >>> 0
se produire et si oui, est-il vraiment souhaitable de le déplacer vers 4294967295? Il semble que cela entraînerait l'exécution de la boucle plusieurs fois plus que nécessaire.this.length
il est impossible de le savoir. Pour toute implémentation "saine", la longueur d'une chaîne ne doit jamais être négative, mais alors on pourrait argumenter que dans un environnement "sain", nous pouvons supposer l'existence d'unethis.length
propriété qui renvoie toujours un nombre entier.Deux raisons:
Le résultat de >>> est une "intégrale"
undefined >>> 0 = 0 (puisque JS essaiera de forcer le LFS au contexte numérique, cela fonctionnera aussi pour "foo" >>> 0, etc.)
Rappelez-vous que les nombres dans JS ont une représentation interne de double. C'est juste un moyen "rapide" de la cohérence d'entrée de base pour la longueur.
Cependant , -1 >>> 0 (oups, probablement pas la longueur souhaitée!)
la source
L'exemple de code Java ci-dessous explique bien:
La sortie est la suivante:
la source