Co robi ~~ („double tilde”) w JavaScript?

Odpowiedzi:

248

Usuwa wszystko po przecinku, ponieważ operatory bitowe domyślnie konwertują swoje operandy na 32-bitowe liczby całkowite ze znakiem. Działa to niezależnie od tego, czy operandy są liczbami zmiennoprzecinkowymi, czy ciągami, a wynikiem jest liczba.

Innymi słowy, daje:

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

tylko jeśli x jest między - (2 31 ) a 2 31 - 1. W przeciwnym razie nastąpi przepełnienie i liczba „zawinie się”.

Może to być uznane za przydatne do konwersji argumentu ciągu funkcji na liczbę, ale zarówno z powodu możliwości przepełnienia, jak i tego, że jest niepoprawny do użycia z liczbami innymi niż całkowite, nie użyłbym go w ten sposób, z wyjątkiem „kodu golfa” ( tj. bezcelowe przycinanie bajtów kodu źródłowego programu kosztem czytelności i niezawodności). Chciałbym użyć +xlub Number(x)zamiast.


Jak to NIE jest NIE

Na przykład liczba -43.2 to:

-43.2 10 = 11111111111111111111111111010101 2

w postaci 32-bitowej liczby binarnej ze znakiem (uzupełnienie dwóch). (JavaScript ignoruje to, co jest po przecinku). Odwrócenie bitów daje:

NIE -43 10 = 00000000000000000000000000101010 2 = 42 10

Ponowne odwrócenie daje:

NOT 42 10 = 11111111111111111111111111010101 2 = -43 10

Różni się to Math.floor(-43.2)tym, że liczby ujemne są zaokrąglane w kierunku zera, a nie od niego. (Funkcja floor, która byłaby równa -44, zawsze zaokrągla w dół do następnej niższej liczby całkowitej, niezależnie od tego, czy liczba jest dodatnia czy ujemna.)

Proszę wstać
źródło
6
To znaczy, że ~~jest to skrótowy sposób (i być może dobre rozwiązanie?) Do tworzenia funkcji obcinania , ale oczywiście w javascript .
ruffin
4
JSLint będzie narzekać na użycie ~~.
Richard Cook
1
Spróbuj Math.trunc ()
Xitalogy
30

Pierwszy operator ~ wymusza operand na liczbę całkowitą (być może po wymuszeniu wartości na łańcuch lub wartość logiczną), a następnie odwraca najniższe 31 bitów. Oficjalnie wszystkie numery ECMAScript są zmiennoprzecinkowe, ale niektóre liczby są implementowane jako 31-bitowe liczby całkowite w silniku SpiderMonkey.

Możesz go użyć do przekształcenia tablicy 1-elementowej w liczbę całkowitą. Punkty zmiennoprzecinkowe są konwertowane zgodnie z regułą C, tj. obcięcie części ułamkowej.

Drugi operator ~ następnie odwraca bity z powrotem, więc wiesz, że będziesz miał liczbę całkowitą. To nie jest to samo, co wymuszanie wartości logicznej w instrukcji warunku, ponieważ pusty obiekt {} ma wartość true, podczas gdy ~~ {} ma wartość 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
Shanti
źródło
1
Dzięki za wszystkie przykłady tutaj Shanti, to naprawdę pomogło!
Shane Tomlinson
6
także~~undefined // 0
rampion
1
także~~null // 0
chovy
Technicznie masz niewłaściwą kolejność. Drugi ~robi to, co opisałeś pierwszy ~robi i na odwrót. ~Operator jest jednoskładnikowa, operatorzy i interpereted od prawej do lewej ~~Xjest jak ~(~X)nie jak (~~)X(co byłoby błąd składni)
yunzen
20

W ECMAScript 6 odpowiednikiem ~~jest Math.trunc :

Zwraca integralną część liczby poprzez usunięcie wszelkich cyfr ułamkowych. Nie zaokrągla żadnych liczb.

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

Polyfill:

function trunc(x) {
    return x < 0 ? Math.ceil(x) : Math.floor(x);
}
Gajus
źródło
6
Nieoczekiwanie ~~ jest szybsze niż Math.trunc, jsperf.com/math-trunc-vs-double-bitwise-not-operator . Chociaż nie wszystko dotyczy szybkości; czytelność też.
Gajus,
3
Istnieje ważna różnica między ~~ i Math.trunc: jeśli przekażesz ciąg znaków, NaN lub cokolwiek innego niż liczba, Math.trunc zwróci NaN i ~~ zawsze zwróci liczbę, w takich przypadkach zwróci 0.
Buzinas
Math.trunc jest nieznacznie szybszy niż ~~ w Chrome 59+ , według jsperf.com/math-trunc-vs-double-bitwise-not-operator .
Jack Steam
12

~Wydaje się zrobić -(N+1). Więc ~2 == -(2 + 1) == -3jeśli zrobisz to ponownie na -3, to odwróci to: ~-3 == -(-3 + 1) == 2Prawdopodobnie po prostu przekształca ciąg znaków na liczbę w okrągły sposób.

Zobacz ten wątek: http://www.sitepoint.com/forums/showthread.php?t=663275

Bardziej szczegółowe informacje są również dostępne tutaj: http://dreaminginjavascript.wordpress.com/2008/07/04/28/

Richard Marskell - Drackir
źródło
Dzięki za linki Drackir!
Shane Tomlinson
7

Biorąc pod uwagę, ~Nznaczy -(N+1), ~~Nto potem -(-(N+1) + 1). Co oczywiście prowadzi do zgrabnej sztuczki .

James Sumners
źródło
Muszę przewinąć w dół do komentarza Matta, aby zobaczyć, jak jest właściwie używany;)
mplungjan 30.10.10
3

Tylko trochę ostrzeżenia. Inne odpowiedzi tutaj wpędziły mnie w kłopoty.

Ma to na celu usunięcie czegokolwiek po przecinku liczby zmiennoprzecinkowej, ale ma kilka przypadków narożnych, które sprawiają, że jest to ryzyko błędu. Polecam unikanie ~~.

Po pierwsze ~~ nie działa na bardzo dużych liczbach.

~~1000000000000 == -727279968

Alternatywnie, użyj Math.trunc()(jak wspomniano Gajus, Math.trunc()zwraca całkowitą część liczby zmiennoprzecinkowej, ale jest dostępna tylko w JavaScript zgodnym z ECMAScript 6). Zawsze możesz stworzyć własne Math.trunc()dla środowisk innych niż ECMAScript-6, wykonując następujące czynności:

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

Napisałem blog na ten temat w celach informacyjnych: http://bitlords.blogspot.com/2016/08/the-double-tilde-x-technique-in.html

JSideris
źródło
1

Oto przykład, w jaki sposób można efektywnie korzystać z tego operatora, gdy jego użycie ma sens:

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

Źródło:

Zobacz rozdział Interakcja z punktami

cssyphus
źródło
1

Konwertowanie ciągów na liczby

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

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

źródło

Mikrofon
źródło
1

Tylda (~) ma algorihm - (N + 1)

Na przykład:

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

Podwójna tylda to - (- (N + 1) +1)

Na przykład:

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

Potrójna tylda to - (- (- (N + 1) +1) +1)

Na przykład:

~~~2 = -(-(-(2+1)+1)+1) = -3
~~~3 = -(-(-(3+1)+1)+1) = -4
CroMagnon
źródło