Estaba mirando el código de Mozilla que agregaba un método de filtro a Array y tenía una línea de código que me confundía.
var len = this.length >>> 0;
Nunca he visto >>> usado en JavaScript antes.
¿Qué es y para qué sirve?
javascript
operators
bit-shift
Kenneth J
fuente
fuente
Array.prototype.push
/Array.prototype.pop
- hexmen.com/blog/2006/12/push-and-pop (aunque hizo las pruebas, jaja).Respuestas:
No solo convierte números que no son números en números, sino que los convierte en números que se pueden expresar como entradas de 32 bits sin signo.
Aunque los números de JavaScript son flotantes de doble precisión (*), los operadores de bits (
<<
,>>
,&
,|
y~
) se definen en términos de operaciones de enteros de 32 bits. Hacer una operación a nivel de bit convierte el número a un int con signo de 32 bits, perdiendo cualquier fracción y bits de lugar superior a 32, antes de hacer el cálculo y luego volver a convertirlo en Número.Entonces, hacer una operación bit a bit sin efecto real, como un desplazamiento hacia la derecha de 0 bits
>>0
, es una forma rápida de redondear un número y asegurarse de que esté en el rango int de 32 bits. Además, el>>>
operador triple , después de realizar su operación sin signo, convierte los resultados de su cálculo en Número como un entero sin signo en lugar del entero con signo que hacen los demás, por lo que puede usarse para convertir negativos al complemento de dos bits de 32 bits versión como un gran número. Utilizando>>>0
garantiza que tenga un número entero entre 0 y 0xFFFFFFFF.En este caso, esto es útil porque ECMAScript define los índices de matriz en términos de entradas de 32 bits sin signo. Entonces, si está tratando de implementar
array.filter
de una manera que duplica exactamente lo que dice el estándar ECMAScript Fifth Edition, debería enviar el número a int de 32 bits sin signo de esta manera.(En realidad hay poca necesidad práctica de esto como es de esperar la gente no va a ser la creación
array.length
de0.5
,-1
,1e21
o'LEMONS'
. Pero esto es autores de JavaScript que estamos hablando, así que nunca se sabe ...)Resumen:
(*: bueno, se definen como comportarse como flotadores. No me sorprendería si algún motor de JavaScript realmente usara ints cuando pudiera, por razones de rendimiento. Pero eso sería un detalle de implementación que no podría tomar. Ventaja de.)
fuente
RangeError: invalid array length
.Array.prototype.filter.call
), por lo quearray
podría no ser realArray
: podría ser alguna otra clase definida por el usuario. (Por desgracia, no puede ser fiable un NodeList, que es cuando usted realmente quiere hacer eso, ya que es un objeto host que las hojas el único lugar en que realmente haría que como el.arguments
Seudo-Array.)if
declaración para esto al tratar de identificar que el lado izquierdo de la evaluación no era un int?'lemons'>>>0 === 0 && 0 >>>0 === 0
evalúa como verdadero? a pesar de que los limones es obviamente una palabra ..?El operador de desplazamiento a la derecha sin signo se utiliza en todas las implementaciones de métodos de matriz extra de Mozilla, para garantizar que la
length
propiedad sea un entero de 32 bits sin signo .La
length
propiedad de los objetos de matriz se describe en la especificación como:Este operador es la forma más corta de lograrlo, internamente los métodos de matriz usan la
ToUint32
operación, pero ese método no es accesible y existe en la especificación para propósitos de implementación.Las implementaciones adicionales de la matriz de Mozilla intentan cumplir con ECMAScript 5 , mire la descripción del
Array.prototype.indexOf
método (§ 15.4.4.14):Como puede ver, solo quieren reproducir el comportamiento del
ToUint32
método para cumplir con la especificación ES5 en una implementación de ES3, y como dije antes, el operador de desplazamiento a la derecha sin firmar es la forma más fácil.fuente
ToUint32
parece un poco innecesario.Array.prototype
métodos son intencionalmente genéricos , se pueden usar en objetos similares a una matriz, por ejemploArray.prototype.indexOf.call({0:'foo', 1:'bar', length: 2}, 'bar') == 1;
. Elarguments
objeto también es un buen ejemplo. Para los objetos de matriz pura , es imposible cambiar el tipo delength
propiedad, ya que implementan un método interno especial [[Put
]], y cuando se realiza una asignación a lalength
propiedad, nuevamente se convierteToUint32
y se toman otras acciones, como eliminar los índices anteriores la nueva duración ...Ese es el operador de desplazamiento de bit derecho sin signo . La diferencia entre este y el operador de desplazamiento a la derecha firmado poco , es que el no firmada operador de desplazamiento a la derecha bits ( >>> ) se llena de ceros de la izquierda, y el firmado operador de desplazamiento de bits a la derecha ( >> ) se llena con el bit de signo, por lo tanto preservando el signo del valor numérico cuando se desplaza.
fuente
>>>
convierte en un número entero, que unario+
no hace.Driis ha explicado suficientemente qué es el operador y qué hace. Aquí está el significado detrás de esto / por qué se usó:
Cambiar cualquier dirección por
0
sí devuelve el número original y se lanzaránull
a0
. Parece que el código de ejemplo que está viendo está usandothis.length >>> 0
para asegurarse de quelen
sea numérico, incluso sithis.length
no está definido.Para muchas personas, las operaciones bit a bit no están claras (y Douglas Crockford / jslint sugiere no usar tales cosas). No significa que sea incorrecto hacerlo, pero existen métodos más favorables y familiares para hacer que el código sea más legible. Una forma más clara para asegurarse de que
len
es0
es cualquiera de los dos métodos siguientes.o
fuente
NaN
... Por ejemplo+{}
... Probablemente sea mejor combinar los dos:+length||0
>>>
es la unsigned operador de desplazamiento a la derecha ( ver p. 76 de la especificación JavaScript 1.5 ), en oposición a la>>
, el firmado operador de desplazamiento a la derecha.>>>
cambia los resultados del desplazamiento de números negativos porque no conserva el bit de signo al desplazarse . Las consecuencias de esto se pueden entender por ejemplo, de un intérprete:Entonces, lo que probablemente se pretende hacer aquí es obtener la longitud, o 0 si la longitud no está definida o no es un número entero, según el
"cabbage"
ejemplo anterior. Creo que en este caso es seguro asumir quethis.length
nunca lo será< 0
. Sin embargo, diría que este ejemplo es un truco desagradable , por dos razones:El comportamiento de
<<<
cuando se usan números negativos, un efecto secundario probablemente no intencionado (o probable que ocurra) en el ejemplo anterior.La intención del código no es obvia , como lo verifica la existencia de esta pregunta.
La mejor práctica es probablemente usar algo más legible a menos que el rendimiento sea absolutamente crítico:
fuente
-1 >>> 0
y, de ser así, es realmente deseable cambiarlo a 4294967295? Parece que esto haría que el ciclo se ejecute varias veces más de lo necesario.this.length
, es imposible saberlo. Para cualquier implementación "sana", la longitud de una cadena nunca debe ser negativa, pero entonces uno podría argumentar que en un ambiente "sano" podemos asumir la existencia de unathis.length
propiedad que siempre devuelve un número entero.Dos razones:
El resultado de >>> es una "integral"
indefinido >>> 0 = 0 (dado que JS intentará forzar el LFS al contexto numérico, esto también funcionará para "foo" >>> 0, etc.)
Recuerde que los números en JS tienen una representación interna de doble. Es solo una forma "rápida" de cordura de entrada básica para la longitud.
Sin embargo , -1 >>> 0 (¡Uy, probablemente no sea la longitud deseada!)
fuente
El código Java de muestra a continuación explica bien:
La salida es la siguiente:
fuente