Wie ändert !! ~ (nicht Tilde / Bang Bang Tilde) das Ergebnis eines Array-Methodenaufrufs 'enthält / eingeschlossen'?

95

Wenn Sie die Kommentare auf der jQuery- inArraySeite hier lesen , gibt es eine interessante Erklärung:

!!~jQuery.inArray(elm, arr) 

Ich glaube, ein doppeltes Ausrufezeichen konvertiert das Ergebnis in einen Typ booleanmit dem Wert von true. Was ich nicht verstehe, ist die Verwendung des ~Operators tilde ( ) in all dem?

var arr = ["one", "two", "three"];
if (jQuery.inArray("one", arr) > -1) { alert("Found"); }

Überarbeitung der ifAnweisung:

if (!!~jQuery.inArray("one", arr)) { alert("Found"); }

Nervenzusammenbruch:

jQuery.inArray("one", arr)     // 0
~jQuery.inArray("one", arr)    // -1 (why?)
!~jQuery.inArray("one", arr)   // false
!!~jQuery.inArray("one", arr)  // true

Mir ist auch aufgefallen, dass das Ergebnis ist, wenn ich die Tilde nach vorne lege -2 .

~!!~jQuery.inArray("one", arr) // -2

Ich verstehe den Zweck der Tilde hier nicht. Kann es bitte jemand erklären oder mich auf eine Ressource hinweisen?

user717236
quelle
50
Wer so Code schreiben möchte, muss sich von der Tastatur entfernen.
Kirk Woll
12
@ KirkWoll: Warum? ~jQuery.inArray()ist tatsächlich sehr nützlich - möglicherweise sogar ein sehr guter Grund, warum die Suchfunktionen -1wegen eines Fehlers zurückkehren (der einzige Wert, dessen Zweierkomplement falsch ist). Sobald Sie den Trick gesehen und verstanden haben, ist er meiner Meinung nach noch besser lesbar als != -1.
Amadan
9
@ Amadan - nein. Einfach nein. Im Ernst, ich kann nicht glauben, dass Sie !!~für irgendetwas verteidigen .
Kirk Woll
24
Das Problem ist, es ist nur das: Ein "Trick". Der Hauptunterschied zwischen if (x != -1)und if (~x)für mich besteht darin, dass Ersteres tatsächlich ausdrückt, was Sie vorhaben. Letzteres drückt aus, dass Sie etwas ganz anderes tun möchten ("Bitte konvertieren Sie meine 64-Bit-Zahl in eine 32-Bit-Ganzzahl und prüfen Sie, ob das bitweise NICHT dieser Ganzzahl wahr ist"), wobei Sie zufällig das gewünschte Ergebnis erzielen ein Fall.
JimmiTh
10
>= 0wahrscheinlich war nicht leet genug, so dass die mehr kryptische !!~verwendet wurde.
Yoshi

Antworten:

56

Der Tilde-Operator ist überhaupt nicht Teil von jQuery - er ist ein bitweiser NOT-Operator in JavaScript.

Siehe Das große Geheimnis der Tilde (~) .

Sie erhalten seltsame Zahlen in Ihren Experimenten, weil Sie eine bitweise logische Operation für eine Ganzzahl ausführen (die, soweit ich weiß, als Zweierkomplement oder ähnliches gespeichert werden kann ...)

Das Zweierkomplement erklärt, wie eine Zahl binär dargestellt wird. Ich glaube ich hatte recht.

pglhall
quelle
3
Fest! (Es wurde in einen anderen Link geändert, der
seltsamerweise
121

Es gibt einen bestimmten Grund, vor dem Sie manchmal ~angewendet sehen$.inArray .

Grundsätzlich,

~$.inArray("foo", bar)

ist ein kürzerer Weg zu tun

$.inArray("foo", bar) !== -1

$.inArrayGibt den Index des Elements im Array zurück, wenn das erste Argument gefunden wird, und -1, wenn es nicht gefunden wird. Dies bedeutet, dass Sie keinen booleschen Vergleich durchführen können, wenn Sie nach einem Booleschen Wert von "Ist dieser Wert im Array?" Suchen, da -1 ein wahrheitsgemäßer Wert ist und wenn $ .inArray 0 (einen falschen Wert) zurückgibt ) bedeutet, dass es tatsächlich im ersten Element des Arrays gefunden wird.

Die Anwendung von ~Bit - Operator bewirkt -1werden 0, und verursacht 0 werden `-1. Wenn Sie den Wert im Array nicht finden und das bitweise NICHT anwenden, erhalten Sie einen falschen Wert (0). Alle anderen Werte geben Zahlen ungleich 0 zurück und stellen ein wahres Ergebnis dar.

if (~$.inArray("foo", ["foo",2,3])) {
    // Will run
}

Und es wird wie vorgesehen funktionieren.

Yahel
quelle
2
Wie gut wird dies in Browsern unterstützt (jetzt im Jahr 2014?) Oder wurde es die ganze Zeit perfekt unterstützt?
Explosion Pills
Ich wäre überrascht, wenn grundlegende Operationen wie diese nicht perfekt wären.
Pcarvalho
104

!!~exprbewertet bis falsewann exprist -1anders true.
Es ist dasselbe wie expr != -1nur kaputt *


Dies funktioniert , weil bitweise JavaScript-Operationen die Operanden in vorzeichenbehaftete 32-Bit-Ganzzahlen im Zweierkomplementformat konvertieren. Somit !!~-1wird wie folgt bewertet:

   -1 = 1111 1111 1111 1111 1111 1111 1111 1111b // two's complement representation of -1
  ~-1 = 0000 0000 0000 0000 0000 0000 0000 0000b // ~ is bitwise not (invert all bits)
   !0 = true                                     // ! is logical not (true for falsy)
!true = false                                    // duh

Bei einem anderen Wert als -1wird mindestens ein Bit auf Null gesetzt. Wenn Sie es umkehren, entsteht ein wahrer Wert. bewirbt sich! Bediener zweimal auf einen truthy Wert wieder boolean wahr.

Bei Verwendung mit .indexOf()und möchten wir nur überprüfen, ob das Ergebnis ist -1oder nicht:

!!~"abc".indexOf("d") // indexOf() returns -1, the expression evaluates to false
!!~"abc".indexOf("a") // indexOf() returns  0, the expression evaluates to true
!!~"abc".indexOf("b") // indexOf() returns  1, the expression evaluates to true

* * !!~8589934591 als falsch ausgewertetGräuelkann nicht zuverlässig zum Testen verwendet werden -1.

Salman A.
quelle
1
In einer stabilen Bibliothek sehe ich kein Problem bei der Verwendung ~foo.indexOf(bar), es sind keine signifikanten Einsparungen bei Zeichen oder Leistung, aber es ist eine relativ häufige Abkürzung in der gleichen Weise foo = foo || {}.
zzzzBov
6
Es ist kein Problem ... zumindest nicht, bis jemand anderes aufgefordert wird, mit Ihrem Code fortzufahren.
Salman A
1
@ahsteele, ich kenne diese Regel sehr gut, aber bitweise Operatoren sind Teil jeder Programmiersprache, die mir einfällt. Ich versuche, auf eine Weise zu programmieren, die für jemanden lesbar ist, der Code lesen kann . Ich höre nicht auf, Funktionen einer Sprache zu verwenden, nur weil jemand anderes sie nicht versteht, sonst könnte ich sie nicht einmal verwenden!! .
zzzzBov
Genau genommen hat >= 0es nicht das gleiche Verhalten wie !!~. !== -1es ist näher.
Peter Olson
33

~foo.indexOf(bar)ist eine gebräuchliche Abkürzung, foo.contains(bar)weil diecontains Funktion nicht vorhanden ist.

In der Regel ist die Umwandlung in Boolesche Werte aufgrund des JavaScript-Konzepts "falscher" Werte nicht erforderlich. In diesem Fall wird er verwendet, um die Ausgabe der Funktion auf trueoder zu erzwingen false.

zzzzBov
quelle
6
+1 Diese Antwort erklärt das "Warum" besser als die akzeptierte Antwort.
Nalply
18

jQuery.inArray()gibt -1für "nicht gefunden" zurück, dessen Komplement ( ~) ist 0. Somit ~jQuery.inArray()liefert einen falsy Wert ( 0) für „nicht gefunden“, und einen truthy Wert (eine negative ganze Zahl ist ) für „gefunden“. !!wird dann die Falschheit / Wahrheit in echte Boolesche false/ formalisieren true. Also, !!~jQuery.inArray()wird truefür "gefunden" und falsefür "nicht gefunden" geben.

Amadan
quelle
13

Das ~für alle 4 Bytes intentspricht dieser Formel-(N+1)

SO

~0   = -(0+1)   // -1
~35  = -(35+1)  // -36 
~-35 = -(-35+1) //34 
Mina Gabriel
quelle
3
Dies ist nicht immer der Fall, da (zum Beispiel) ~2147483648 != -(2147483648 + 1).
Frxstrem
10

Der ~Operator ist der bitweise Komplementoperator. Das Ganzzahlergebnis von inArray()ist entweder -1, wenn das Element nicht gefunden wird, oder eine nicht negative Ganzzahl. Das bitweise Komplement von -1 (binär als alle 1 Bits dargestellt) ist Null. Das bitweise Komplement einer nicht negativen ganzen Zahl ist immer ungleich Null.

Dies ist !!~ider Fall, truewenn die Ganzzahl "i" eine nicht negative Ganzzahl ist und falsewenn "i" genau -1 ist.

Beachten Sie, dass ~der Operand immer zur Ganzzahl gezwungen wird. Das heißt, es werden nicht ganzzahlige Gleitkommawerte in ganzzahlige sowie nicht numerische Werte gezwungen.

Spitze
quelle
10

Tilde ist bitweise NICHT - es invertiert jedes Bit des Wertes. Als Faustregel gilt: Wenn Sie ~eine Zahl verwenden, wird ihr Vorzeichen invertiert und 1 abgezogen.

Wenn Sie dies tun ~0, erhalten Sie -1 (0 invertiert ist -0, subtrahieren 1 ist -1).

Es ist im Wesentlichen eine ausgefeilte, super-mikrooptimierte Methode, um einen Wert zu erhalten, der immer boolesch ist.

Joe
quelle
8

Sie haben Recht: Dieser Code wird zurückgegeben, falsewenn der indexOfAufruf -1 zurückgibt. sonst true.

Wie Sie sagen, wäre es viel sinnvoller, so etwas zu verwenden

return this.modifiedPaths.indexOf(path) !== -1;
LukeH
quelle
1
Aber das sind noch 3 Bytes, die an den Client gesendet werden müssen! edit: (übrigens nur ein Scherz, habe meinen Kommentar gepostet und festgestellt, dass es nicht offensichtlich ist (was sowohl traurig als auch albern ist))
Wesley Murch
@Wesley: Das stimmt, aber es muss nur einmal an jeden Client gesendet werden , vorausgesetzt, der Client wird das zwischenspeichern .js. Allerdings könnten sie >=0eher als !==-1- keine zusätzlichen Bytes zum Senden verwenden und noch besser lesbar als die Bit-Twiddling-Version.
LukeH
2
Wer trollt wen hier? ;) Ich denke, ich habe es als selbstverständlich angesehen, dass das Schreiben von lesbarem Code besser ist als kryptischer voroptimierter Code, der diese Art von Fragen generiert. Minimieren Sie es einfach später und schreiben Sie jetzt lesbaren, verständlichen Code.
Wesley Murch
2
Persönlich würde ich sagen, dass > -1das noch besser lesbar ist, aber das ist wahrscheinlich sehr subjektiv.
Yoshi
6

Der ~Operator ist der bitweise NICHT-Operator. Dies bedeutet, dass es eine Zahl in binärer Form annimmt und alle Nullen in Einsen und Einsen in Nullen umwandelt.

Zum Beispiel ist die Zahl 0 in binär 0000000, während -1 ist 11111111. Ebenso ist 1 00000001binär, während -2 ist 11111110.

Frxstrem
quelle
3

Ich vermute, dass es da ist, weil es ein paar Zeichen kürzer ist (welche Bibliotheksautoren immer danach suchen). Es werden auch Operationen verwendet, die beim Kompilieren in den nativen Code nur wenige Maschinenzyklen dauern (im Gegensatz zum Vergleich mit einer Zahl).

Ich stimme einer anderen Antwort zu, dass dies ein Overkill ist, aber möglicherweise in einer engen Schleife sinnvoll sein kann (erfordert jedoch eine Schätzung des Leistungsgewinns, kann sich andernfalls als vorzeitige Optimierung herausstellen).

Alexander Pawlow
quelle
2

Ich nehme an, da es sich um eine bitweise Operation handelt, ist dies der schnellste (rechnerisch kostengünstige) Weg, um zu überprüfen, ob der Pfad in modifizierten Pfaden angezeigt wird.

panos2point0
quelle
1

Wie (~(-1)) === 0, so:

!!(~(-1)) === Boolean(~(-1)) === Boolean(0) === false
Ingenieur
quelle
1
Das mag richtig sein, aber ist es eine nützliche Erklärung für den Fragesteller? Überhaupt nicht. Wenn ich es zunächst nicht verstanden hätte, würde eine knappe Antwort wie diese nicht helfen.
Spudley
Ich denke, diese Antwort macht Sinn. Wenn Sie ein mathematisches Gehirn haben, können Sie deutlich sehen, welche Teile sich bei jedem Schritt ändern. Ist es die beste Antwort auf diese Frage? Nein, aber es ist nützlich, ich denke schon! +1
Taylor Lopez