Cosa fa ~~ ("double tilde") in Javascript?


Risposte:


248

Rimuove tutto dopo il punto decimale perché gli operatori bit a bit convertono implicitamente i loro operandi in numeri interi a 32 bit con segno. Funziona indipendentemente dal fatto che gli operandi siano numeri o stringhe (in virgola mobile) e il risultato sia un numero.

In altre parole, produce:

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

solo se x è compreso tra - (2 31 ) e 2 31 - 1. Altrimenti, si verificherà un overflow e il numero si "avvolgerà".

Questo può essere considerato utile per convertire l'argomento stringa di una funzione in un numero, ma sia a causa della possibilità di overflow sia che non è corretto per l'uso con numeri non interi, non lo userei in questo modo tranne che per "code golf" ( cioè eliminando inutilmente i byte dal codice sorgente del programma a scapito della leggibilità e della robustezza). Vorrei usare +xo Number(x)invece.


Come questo è il NOT del NOT

Il numero -43.2, ad esempio è:

-43.2 10 = 11111111111111111111111111010101 2

come un numero binario a 32 bit con segno (complemento a due). (JavaScript ignora ciò che è dopo il punto decimale.) L'inversione dei bit dà:

NOT -43 10 = 00000000000000000000000000101010 2 = 42 10

L'inversione di nuovo dà:

NOT 42 10 = 11111111111111111111111111010101 2 = -43 10

Ciò differisce dal fatto Math.floor(-43.2)che i numeri negativi sono arrotondati verso zero, non lontano da esso. (La funzione floor, che equivarrebbe a -44, arrotonda sempre al successivo numero intero inferiore, indipendentemente dal fatto che il numero sia positivo o negativo.)


6
Vale a dire, ~~è un modo abbreviato (e forse una buona soluzione?) Per creare una funzione troncata , ma ovviamente in javascript .
ruffin,

4
JSLint si lamenterà dell'uso di ~~.
Richard Cook,

1
Prova Math.trunc ()
Xitalogy l'

30

Il primo operatore ~ ​​forza l'operando a un numero intero (possibilmente dopo aver forzato il valore in una stringa o in un valore booleano), quindi inverte i 31 bit più bassi. I numeri ECMAScript ufficiali sono tutti in virgola mobile, ma alcuni numeri sono implementati come numeri interi a 31 bit nel motore SpiderMonkey.

Puoi usarlo per trasformare un array di 1 elemento in un numero intero. I virgola mobile vengono convertiti secondo la regola C, vale a dire. troncamento della parte frazionaria.

Il secondo operatore ~ ​​quindi inverte i bit, quindi sai che avrai un numero intero. Ciò non equivale a forzare un valore su booleano in un'istruzione condition, poiché un oggetto vuoto {} restituisce true, mentre ~~ {} restituisce false.

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

1
Grazie per tutti gli esempi qui Shanti, mi ha davvero aiutato!
Shane Tomlinson,

6
anche~~undefined // 0
rampion

1
anche~~null // 0
chovy

Tecnicamente hai un ordine sbagliato. Il secondo ~fa quello che hai descritto il primo ~e viceversa. L' ~operatore è un operatore unario ed è interpereted da destra a sinistra ~~Xè come ~(~X)non è come (~~)X(che sarebbe un errore di sintassi)
yunzen

21

In ECMAScript 6, l'equivalente di ~~è Math.trunc :

Restituisce la parte integrale di un numero rimuovendo le cifre frazionarie. Non arrotonda alcun numero.

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

Il polyfill:

function trunc(x) {
    return x < 0 ? Math.ceil(x) : Math.floor(x);
}

6
Un po 'sorprendentemente, ~~ è più veloce di Math.trunc, jsperf.com/math-trunc-vs-double-bitwise-not-operator . Tuttavia, non tutto riguarda la velocità; anche leggibilità.
Gajus,

3
C'è una differenza importante tra ~~ e Math.trunc: se passi una stringa, o NaN o qualunque cosa non sia un numero, Math.trunc restituirà NaN e ~~ restituirà sempre un numero, in quei casi, restituirà 0.
Buzinas

Math.trunc è leggermente più veloce di ~~ in Chrome 59+, secondo jsperf.com/math-trunc-vs-double-bitwise-not-operator .
Jack Steam,



4

Solo un avvertimento. Le altre risposte qui mi hanno messo nei guai.

L'intenzione è quella di rimuovere qualsiasi cosa dopo il punto decimale di un numero in virgola mobile, ma ha alcuni casi angolari che lo rendono pericoloso. Consiglierei di evitare ~~.

Innanzitutto, ~~ non funziona su numeri molto grandi.

~~1000000000000 == -727279968

In alternativa, utilizzare Math.trunc()(come indicato da Gajus, Math.trunc()restituisce la parte intera di un numero in virgola mobile ma è disponibile solo in JavaScript conforme a ECMAScript 6). Puoi sempre crearne uno tuo Math.trunc()per ambienti non ECMAScript-6 facendo questo:

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

Ho scritto un post sul blog per riferimento: http://bitlords.blogspot.com/2016/08/the-double-tilde-x-technique-in.html


1

Ecco un esempio di come questo operatore può essere utilizzato in modo efficiente, dove ha senso usarlo:

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

Fonte:

Vedi la sezione Interazione con i punti


1

Conversione di stringhe in numeri

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 è 0

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

fonte


1

Tilde (~) ha un algorihm - (N + 1)

Per l'esame:

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

La doppia tilde è - (- (N + 1) +1)

Per esempio:

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

La tilde tripla è - (- (- (N + 1) +1) +1)

Per esempio:

~~~2 = -(-(-(2+1)+1)+1) = -3
~~~3 = -(-(-(3+1)+1)+1) = -4
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.