Was macht eine Tilde, wenn sie einem Ausdruck vorausgeht?

Antworten:

266

~ist ein bitweiser Operator , der alle Bits in seinem Operanden umdreht.

Wenn Ihre Nummer beispielsweise wäre, wäre 1ihre binäre Darstellung des IEEE 754-Floats (wie JavaScript Zahlen behandelt) ...

0011 1111 1111 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000

So ~wandelt seine Operanden in einem 32 - Bit - Integer (bitweise Operatoren in JavaScript tun) ...

0000 0000 0000 0000 0000 0000 0000 0001

Wenn es eine negative Zahl wäre, würde sie im Zweierkomplement gespeichert: Invertiere alle Bits und addiere 1.

... und dreht dann alle seine Teile um ...

1111 1111 1111 1111 1111 1111 1111 1110

Was nützt es dann? Wann könnte man es jemals benutzen?

Es hat einige Verwendungszwecke. Wenn Sie Low-Level-Sachen schreiben, ist es praktisch. Wenn Sie Ihre Anwendung profiliert und einen Engpass festgestellt haben, kann sie durch bitweise Tricks (als ein mögliches Werkzeug in einer viel größeren Tasche) leistungsfähiger werden .

Es ist auch ein (allgemein) unklarer Trick , indexOf()den gefundenen Rückgabewert in wahrheitsgemäß umzuwandeln (obwohl er nicht als falsch eingestuft wird ), und die Leute verwenden ihn häufig wegen seines Nebeneffekts, Zahlen auf 32 Bit abzuschneiden (und seine Dezimalstelle durch Verdoppeln zu löschen ). effektiv das gleiche wie Math.floor()für positive Zahlen).

Ich sage unklar, weil es nicht sofort offensichtlich ist, wofür es verwendet wird. Im Allgemeinen möchten Sie, dass Ihr Code klar mit anderen Personen kommuniziert, die ihn lesen. Während die Verwendung cool aussehen~ mag , ist sie im Allgemeinen zu clever für sich. :) :)

Es ist jetzt auch weniger relevant, da JavaScript Array.prototype.includes()und hat String.prototype.includes(). Diese geben einen booleschen Wert zurück. Wenn Ihre Zielplattform (en) dies unterstützen, sollten Sie dies bevorzugen, um das Vorhandensein eines Werts in einer Zeichenfolge oder einem Array zu testen.

Alex
quelle
2
Ist böse das richtige Wort? Wenn es funktioniert, würde ich es einfach eine Sprache der Sprache nennen. Es gibt viele Redewendungen. Sobald Sie sie lernen, sind sie nicht unklar. Listenverständnisse sind in Python nicht klar, wenn Sie sie nicht kennen und können mit ausführlicheren Schleifen erreicht werden, aber Sie würden niemals einen Python-Programmierer bitten, sie nicht zu verwenden. Ebenso ist value = value || defaultin JavaScript eine gebräuchliche und gültige Redewendung, solange Sie wissen, wann Sie sie verwenden können und wann nicht.
Gman
3
@gman Ich denke, es ist nicht wirklich wichtig, ob jemand es benutzt oder nicht. Ich denke, der Vergleich des Listenverständnisses (Sprachfunktion) mit diesem ist nicht wirklich dasselbe ( clevere Methode, um die Eingabe zusätzlicher Zeichen zu vermeiden). Wenn Sie der Meinung sind, dass böse Begriffe zu hart sind, können Sie meine Antwort jederzeit bearbeiten.
Alex
2
Vielleicht ist ein häufigeres Beispiel v = t ? a : b;. Ich finde das viel klarer als var v; if (t} { v = a; } else { v = b; }normalerweise über 5 Zeilen verteilt und auch klarer als var v = b; if (t) { v = a; }normalerweise über 4 Zeilen. Aber ich kenne viele Leute, die mit den ? :Betreibern nicht vertraut sind und den zweiten oder dritten Weg bevorzugen würden. Ich finde das erste ist besser lesbar. Ich stimme dem allgemeinen Prinzip zu, mache den Code klar, benutze keine Hacks. Ich denke, ich sehe ~v.indexOf('...')nur sehr klar, wenn ich es gelernt habe.
Gman
9
Wenn Sie in einem großen Unternehmen mit vielen Entwicklern arbeiten, möchten Sie, dass der Code klar geschrieben (ENGLISCH) und gut dokumentiert ist. Bei der Codierung auf hoher Ebene in einer Sprache mit Garbage Collection geht es darum, nicht an binäre Operationen zu denken, und viele Front-End-Entwickler verfügen nicht einmal über Erfahrung in Assemblersprachen.
user2867288
3
Ich würde nicht ~idiomatisch nennen . es ist technisch Teil der Sprache spec , aber es ist nicht so sehr ein Teil der Sprache im allgemeinen Gebrauch .
worc
108

Verwenden Sie es vor einem indexOf() Ausdruck verwenden, erhalten Sie anstelle des direkt zurückgegebenen numerischen Index ein wahrheitsgemäßes / falsches Ergebnis.

Wenn der Rückgabewert ist -1, ~-1liegt es 0daran, dass -1es sich um eine Zeichenfolge aller 1 Bits handelt. Jeder Wert größer oder gleich Null ergibt ein Ergebnis ungleich Null. So,

if (~someString.indexOf(something)) {
}

bewirkt, dass der ifCode ausgeführt wird, wenn sich "etwas" in "someString" befindet. Wenn Sie versuchen zu verwenden.indexOf() direkt als Boolescher Wert zu verwenden, funktioniert dies nicht, da manchmal Null zurückgegeben wird (wenn "etwas" am Anfang der Zeichenfolge steht).

Das funktioniert natürlich auch:

if (someString.indexOf(something) >= 0) {
}

und es ist wesentlich weniger mysteriös.

Manchmal sehen Sie auch Folgendes:

var i = ~~something;

Wenn Sie den ~Operator zweimal so verwenden, können Sie eine Zeichenfolge schnell in eine 32-Bit-Ganzzahl konvertieren. Der erste ~führt die Konvertierung durch und der zweite ~dreht die Bits zurück. Wenn der Operator auf etwas angewendet wird, das nicht in eine Zahl konvertiert werden kann, erhalten Sie natürlich NaNein Ergebnis. ( Bearbeiten - eigentlich ist es die zweite ~, die zuerst angewendet wird, aber Sie bekommen die Idee.)

Spitze
quelle
2
Für diejenigen, die nicht Stück für Stück negieren wollen, ist die Ausführung mit ~ganzen Zahlen gleich -(x + 1).
Fabrício Matté
Scheint so, als ob NEGATIVE numerische Werte in erster Linie auch negative boolesche Werte zurückgeben sollten. Aber nur einer von JS 'scheitert, denke ich?
Wwaawaw
7
@adlwalrus Nun, die Tradition des 0Seins falseund des Nicht-Null-Seins truereicht weit zurück, zumindest bis C in den 70er Jahren und wahrscheinlich viele andere damals moderne Systemprogrammiersprachen. Es liegt wahrscheinlich an der Funktionsweise der Hardware. Viele CPUs setzen nach einer Operation ein Nullbit und haben einen entsprechenden Verzweigungsbefehl, um es zu testen.
Pointy
4
Eine schnellere Möglichkeit, es in ein 32-Bit-Int zu konvertieren, wäre | 0in diesem Fall die einzige Operation.
Alex
@alex in der Tat, obwohl wir der Laufzeit nicht unbedingt vertrauen können, eine einfache Anwendung nicht ~~genau so zu interpretieren .
Pointy
28

Das ~ist Bitwise NOT Operator , ~xist ungefähr das gleiche wie -(x+1). Es ist leichter zu verstehen. So:

~2;    // -(2+1) ==> -3

Überlegen Sie -(x+1). -1kann diese Operation ausführen, um a zu erzeugen 0.

Mit anderen Worten, ~wenn es mit einem Bereich von Zahlenwerten verwendet wird, wird nur für die ein falscher Wert (erzwingen falsevon 0) erzwungen-1 Eingangswert, ansonsten anderen truthy Wert.

Wie wir wissen, -1wird dies allgemein als Sentinel-Wert bezeichnet . Es ist für viele Funktionen verwendet , die >= 0Rückwerte für Erfolg und -1für Versagen in C - Sprache. Welches die gleiche Regel der Rückgabewert vonindexOf() in JavaScript.

Es ist üblich, auf diese Weise das Vorhandensein / Fehlen eines Teilstrings in einem anderen String zu überprüfen

var a = "Hello Baby";

if (a.indexOf("Ba") >= 0) {
    // found it
}
if (a.indexOf("Ba") != -1) { 
    // found it
}

if (a.indexOf("aB") < 0) { 
    // not found
}
if (a.indexOf( "aB" ) == -1) { 
    // not found
}

Es wäre jedoch einfacher, dies ~wie unten beschrieben durchzuführen

var a = "Hello Baby";

~a.indexOf("Ba");         // -7   -> truthy
if (~a.indexOf("Ba")) {   // true
    // found it
}

~a.indexOf("aB");         // 0    -> falsy
!~a.indexOf("aB");        // true
if (!~a.indexOf( "aB" )) {  // true
    // not found
}

Sie kennen JS nicht: Typen & Grammatik von Kyle Simpson

zangw
quelle
1
Es ist definitiv einfacher, zum Nennwert zu verstehen, selbst wenn eine Person den Hintergrund, der es funktioniert, nicht versteht. Ich würde einen zweiten Blick darauf werfen, -(x+1)wenn ich es in einer if-Anweisung sehen würde. Die Tilde sagt mir genau, was sie tut, um die 0-basierte Natur von Javascript zu kompensieren. Je weniger Klammern, desto besser zum Lesen
Regular Joe
In Ihrem anfänglichen Prüfcodeblock könnten Sie weniger eingeben, indem Sie verwenden, if (a.indexOf("Ba") > -1) {// found} //truewas zwar etwas länger als die Tilde-Beispiele ist, aber erheblich weniger als die beiden von Ihnen angegebenen Beispiele und für neue Programmierer var opinion = !~-1 ? 'more' : 'less'verständlich ist.
Hmerman6006
24

~indexOf(item) kommt ziemlich oft vor und die Antworten hier sind großartig, aber vielleicht müssen einige Leute nur wissen, wie man es benutzt und die Theorie "überspringen":

   if (~list.indexOf(item)) {
     // item in list
   } else {
     // item *not* in list
   }
Jorge Bucaran
quelle
1
Ich stimme zu. Airbnb JavaScript Style Guide verbietet ++und --weil sie "übermäßige Trickserei fördern" und dennoch irgendwie ~überlebt haben (im Schatten lauern) github.com/airbnb/javascript/issues/540
Shanimal
@Shanimal Die Alternative ist list.indexOf(item) >= 0oder, ... > -1da Javascript auf Null basiert und sich nicht von Anfang an dafür entschieden hat, dies zu beheben . Darüber hinaus weiß jeder, der in Javascript etwas Sinnvolles tut, nur die Meinung (wie bei Airbnb), ++und obwohl dies --weniger verbreitet ist, kann auf die Bedeutung geschlossen werden.
Normaler Joe
@ RegularJoe Ich stimme dem größten Teil zu. Ich habe persönlich nicht benötigt ++und --in einer Weile wegen primitiver Methoden wie map, forEachusw. Mein Punkt ist , mehr darüber , warum sie nicht auch prüfen , ~übermäßig schwierig , wenn alles , was Standard verwendet Schritt umfasst und Dekrementoperatoren. Etwas zu verbieten, damit CIS101 keinen Sinn ergibt.
Shanimal
11

Für diejenigen, die erwägen, den Tilde-Trick zu verwenden, um aus einem Ergebnis einen wahrheitsgemäßen Wert zu erstellen indexOf, ist es expliziter und hat weniger Magie, stattdessen die includesMethodeString anzuwenden .

'hello world'.includes('hello') //=> true
'hello world'.includes('kittens') //=> false

Beachten Sie, dass dies ab ES 2015 eine neue Standardmethode ist, die in älteren Browsern nicht funktioniert. In Fällen, in denen dies wichtig ist, sollten Sie die Verwendung von String.prototype.includes polyfill in Betracht ziehen .

Diese Funktion ist auch für Arrays mit derselben Syntax verfügbar :

['apples', 'oranges', 'cherries'].includes('apples') //=> true
['apples', 'oranges', 'cherries'].includes('unicorns') //=> false

Hier ist die Array.prototype.includes Polyfill, wenn Sie ältere Browserunterstützung benötigen.

Dana Woodman
quelle
2
Vermeiden Sie die Verwendung von include (). Es wird zum Zeitpunkt des Schreibens in keiner IE-Version (nicht nur in älteren Browsern) unterstützt: developer.mozilla.org/en/docs/Web/JavaScript/Reference/…
Onshop
8
Oder verwenden Sie einfach einen Compiler, damit Sie klareren Code schreiben können, anstatt die Sprache nach dem JS-Interpreter mit dem schlechtesten gemeinsamen Nenner zu schreiben ...
Kyle Baker
2
@ Ben ist richtig, es funktioniert auch nicht in Netscape 4.72.
Mikemaccana