¿Qué hace ~~ ("doble tilde") en Javascript?

Respuestas:

248

Elimina todo después del punto decimal porque los operadores bit a bit convierten implícitamente sus operandos en enteros de 32 bits con signo. Esto funciona si los operandos son números o cadenas (de punto flotante) y el resultado es un número.

En otras palabras, produce:

function(x) {
  if(x < 0) return Math.ceil(x);
  else return Math.floor(x);
}

solo si x está entre - (2 31 ) y 2 31 - 1. De lo contrario, se producirá un desbordamiento y el número se "envolverá".

Esto puede considerarse útil para convertir el argumento de cadena de una función en un número, pero tanto por la posibilidad de desbordamiento como por el hecho de que es incorrecto para usar con números no enteros, no lo usaría de esa manera, excepto para "golf de código" ( es decir recortar bytes sin sentido del código fuente de su programa a expensas de la legibilidad y robustez). Yo usaría +xo en su Number(x)lugar.


Cómo este es el NO del NO

El número -43.2, por ejemplo es:

-43.2 10 = 11111111111111111111111111010101 2

como un número binario de 32 bits con signo (complemento de dos). (JavaScript ignora lo que está después del punto decimal.) Invertir los bits da:

NO -43 10 = 00000000000000000000000000101010 2 = 42 10

Invertir nuevamente da:

NO 42 10 = 11111111111111111111111111010101 2 = -43 10

Esto difiere de Math.floor(-43.2)que los números negativos se redondean hacia cero, no lejos de él. (La función de piso, que sería igual a -44, siempre se redondea al siguiente entero más bajo, independientemente de si el número es positivo o negativo).

Por favor levantese
fuente
66
Es decir, ~~es una forma abreviada (y posiblemente una buena solución) para crear una función truncada , pero obviamente en JavaScript .
ruffin
44
JSLint se quejará del uso de ~~.
Richard Cook
1
Prueba Math.trunc ()
Xitalogy
30

El primer operador ~ fuerza el operando a un número entero (posiblemente después de forzar el valor a una cadena o un booleano), luego invierte los 31 bits más bajos. Oficialmente, los números de ECMAScript son todos de punto flotante, pero algunos números se implementan como enteros de 31 bits en el motor SpiderMonkey.

Puede usarlo para convertir una matriz de 1 elemento en un entero. Los puntos flotantes se convierten de acuerdo con la regla C, es decir. truncamiento de la parte fraccional.

El segundo operador ~ luego invierte los bits, para que sepa que tendrá un número entero. Esto no es lo mismo que coaccionar un valor a booleano en una declaración de condición, porque un objeto vacío {} se evalúa como verdadero, mientras que ~~ {} se evalúa como falso.

js>~~"yes"
0
js>~~3
3
js>~~"yes"
0
js>~~false
0
js>~~""
0
js>~~true
1
js>~~"3"
3
js>~~{}
0
js>~~{a:2}
0
js>~~[2]
2
js>~~[2,3]
0
js>~~{toString: function() {return 4}}
4
js>~~NaN
0
js>~~[4.5]
4
js>~~5.6
5
js>~~-5.6
-5
Shanti
fuente
1
Gracias por todos los ejemplos aquí Shanti, ¡realmente ayudó!
Shane Tomlinson el
66
también~~undefined // 0
rampion
1
también~~null // 0
chovy
Técnicamente tienes el orden incorrecto. El segundo ~hace lo que usted describió ~, y viceversa. El ~operador es un operador unario y está interperado de derecha a izquierda ~~Xes como ~(~X)no (~~)X(lo que sería un error de sintaxis)
yunzen
21

En ECMAScript 6, el equivalente de ~~es Math.trunc :

Devuelve la parte integral de un número eliminando los dígitos fraccionarios. No redondea ningún número.

Math.trunc(13.37)   // 13
Math.trunc(42.84)   // 42
Math.trunc(0.123)   //  0
Math.trunc(-0.123)  // -0
Math.trunc("-1.123")// -1
Math.trunc(NaN)     // NaN
Math.trunc("foo")   // NaN
Math.trunc()        // NaN

El polyfill:

function trunc(x) {
    return x < 0 ? Math.ceil(x) : Math.floor(x);
}
Gajus
fuente
66
Sorprendentemente, ~~ es más rápido que Math.trunc, jsperf.com/math-trunc-vs-double-bitwise-not-operator . Sin embargo, no todo se trata de velocidad; legibilidad también.
Gajus
3
Hay una diferencia importante entre ~~ y Math.trunc: si pasa una cadena, o NaN o cualquier cosa que no sea un número, Math.trunc devolverá NaN, y ~~ siempre devolverá un número, en esos casos, devolverá 0.
Buzinas
Math.trunc es ligeramente más rápido que ~~ en Chrome 59+, según jsperf.com/math-trunc-vs-double-bitwise-not-operator .
Jack Steam
7

Dado ~Nes -(N+1), ~~Nes entonces -(-(N+1) + 1). Lo que, evidentemente, lleva a un buen truco .

James Sumners
fuente
Tiene que desplazarse hacia abajo para ver el comentario de Matt para verlo en el uso adecuado;)
mplungjan
4

Solo un poco de advertencia. Las otras respuestas aquí me metieron en problemas.

La intención es eliminar cualquier cosa después del punto decimal de un número de coma flotante, pero tiene algunos casos de esquina que lo convierten en un peligro de error. Recomiendo evitar ~~.

Primero, ~~ no funciona en números muy grandes.

~~1000000000000 == -727279968

Como alternativa, use Math.trunc()(como mencionó Gajus, Math.trunc()devuelve la parte entera de un número de coma flotante pero solo está disponible en JavaScript compatible con ECMAScript 6). Siempre puede hacer lo suyo Math.trunc()para entornos que no sean ECMAScript-6 haciendo esto:

if(!Math.trunc){
    Math.trunc = function(value){
        return Math.sign(value) * Math.floor(Math.abs(value));
    }
}

Escribí una publicación de blog sobre esto para referencia: http://bitlords.blogspot.com/2016/08/the-double-tilde-x-technique-in.html

JSideris
fuente
1

Aquí hay un ejemplo de cómo este operador se puede usar de manera eficiente, donde tiene sentido usarlo:

leftOffset = -(~~$('html').css('padding-left').replace('px', '') + ~~$('body').css('margin-left').replace('px', '')),

Fuente:

Ver sección Interactuar con puntos

cssyphus
fuente
1

Convertir cadenas a números

console.log(~~-1);    // -1
console.log(~~0);     // 0
console.log(~~1);     // 1
console.log(~~"-1");  // -1
console.log(~~"0");   // 0
console.log(~~"1");   // 1
console.log(~~true);  // 1
console.log(~~false); // 0

~ -1 es 0

if (~someStr.indexOf("a")) {
  // Found it
} else  {
  // Not Found
}

fuente

Miguel
fuente
1

Tilde (~) tiene un algoritmo - (N + 1)

Por ejemplo:

~0 = -(0+1) = -1
~5 = -(5+1) = -6
~-7 = -(-7+1) = 6

La tilde doble es - (- (N + 1) +1)

Por ejemplo:

~~5 = -(-(5+1)+1) = 5
~~-3 = -(-(-3+1)+1) = -3

La tilde triple es - (- (- (N + 1) +1) +1)

Por ejemplo:

~~~2 = -(-(-(2+1)+1)+1) = -3
~~~3 = -(-(-(3+1)+1)+1) = -4
CroMagnon
fuente