Was ist der !! (nicht nicht) Operator in JavaScript?

3106

Ich habe einen Code gesehen, der einen Operator zu verwenden scheint, den ich nicht kenne, und zwar in Form von zwei Ausrufezeichen : !!. Kann mir bitte jemand sagen, was dieser Operator macht?

Der Kontext, in dem ich das sah, war:

this.vertical = vertical !== undefined ? !!vertical : this.vertical;
Hexagon-Theorie
quelle
945
Erinnern Sie sich an es durch "Knall, Knall, Sie sind boolean"
Gus
75
Tun Sie nicht, was dort zitiert wird. Tun Sie es if(vertical !== undefined) this.vertical = Boolean(vertical);- es ist viel sauberer und klarer, was vor sich geht, erfordert keine unnötige Zuweisung, ist Standard und genauso schnell (bei aktuellem FF und Chrome) jsperf.com/boolean-conversion-speed .
Phil H
73
!! ist kein Operator. Es ist nur das! Betreiber zweimal.
Vivek
11
Nur für die Aufzeichnung, Boolean(5/0)ist nicht das gleiche wie!!5/0
schabluk
63
@schabluk, für die Aufzeichnung, ist die Reihenfolge der Operationen der Grund, !!5/0der Infinityeher produziert als true, wie von produziert Boolean(5/0). !!5/0ist gleichbedeutend mit (!!5)/0- aka true/0-, da der !Operator eine höhere Priorität als der /Operator hat. Wenn Sie 5/0mit einem Doppelknall booleanisieren möchten , müssen Sie verwenden !!(5/0).
Matty

Antworten:

2746

Konvertiert Objectin boolean. Wenn es Falsey (zB 0, null, undefined, etc.), wird es sein false, andernfalls true.

!oObject  // inverted boolean
!!oObject // non inverted boolean so true boolean representation

Ist !!also kein Operator, es ist nur der !Operator zweimal.

Beispiel aus der realen Welt "IE-Version testen":

const isIE8 = !! navigator.userAgent.match(/MSIE 8.0/);  
console.log(isIE8); // returns true or false 

Wenn Sie ⇒

console.log(navigator.userAgent.match(/MSIE 8.0/));  
// returns either an Array or null  

Aber wenn Sie ⇒

console.log(!!navigator.userAgent.match(/MSIE 8.0/));  
// returns either true or false
stevehipwell
quelle
123
Es konvertiert einen nicht-booleschen Wert in einen invertierten booleschen Wert (z. B.! 5 wäre falsch, da 5 in JS ein nicht falscher Wert ist) und invertiert diesen Wert, sodass Sie den ursprünglichen Wert als booleschen Wert erhalten (also !! 5) wahr sein).
Chuck
111
Eine einfache Möglichkeit, es zu beschreiben, ist: Boolean (5) === !! 5; Gleiches Casting, weniger Charaktere.
Micah Snyder
39
Dies wird verwendet, um wahrheitsgemäße Werte in boolesche Werte und falsche Werte in boolesche Werte für falsch umzuwandeln.
Thetoolman
13
@Micah Snyder Achten Sie darauf, dass es in JavaScript besser ist, boolesche Grundelemente zu verwenden, als Objekte zu erstellen, die boolesche Werte mit neuem Boolean () enthalten. Hier ist ein Beispiel, um den Unterschied zu sehen: jsfiddle.net/eekbu
victorvartan
4
Soweit ich weiß, ist dieses Bang-Bang-Muster in einer if (… _ - Anweisung nicht nützlich; nur in einer return-Anweisung einer Funktion, die einen Booleschen
Wert zurückgeben
854

Es ist eine schrecklich dunkle Art, eine Typkonvertierung durchzuführen.

!ist NICHT . So !trueist falseund !falseist true. !0ist trueund !1ist false.

Sie konvertieren also einen Wert in einen Booleschen Wert, invertieren ihn dann und invertieren ihn erneut.

// Maximum Obscurity:
val.enabled = !!userId;

// Partial Obscurity:
val.enabled = (userId != 0) ? true : false;

// And finally, much easier to understand:
val.enabled = (userId != 0);
Tom Ritter
quelle
74
!! false = false. !! true = true
cllpse
89
Ist die Variante "viel einfacher zu verstehen" hier wirklich viel einfacher zu verstehen? Die Prüfung gegen 0 ist keine tatsächliche Prüfung gegen 0, aber eine Prüfung gegen die etwas seltsame Liste von Werten, die Javascript als gleich 0 betrachtet, userId ? true : false macht deutlicher, dass eine Konvertierung stattfindet, und behandelt den Fall, in dem der Wert von userId möglicherweise explizit festgelegt wurdeundefined
Ben Regenspan
54
Mein Gehirn hat keine Probleme beim Dekodieren !!varin Boolean(var)... und !!ist schneller (weniger zu verarbeitende Anweisungen) und kürzer als die Alternativen.
AdamJLev
7
@ RickyClarkson dient hauptsächlich der Lesbarkeit, da es syntaktisch nicht erforderlich ist. Einige verwenden die Konvention, eine Bedingung immer in Klammern zu setzen, um sie vom Rest des Ausdrucks abzuheben.
Dave Rager
8
Ich bin damit nicht einverstanden. userId != 0gilt für null, NaNund undefined, aber falsch für false. Wenn Sie genau dieses Verhalten wünschen, sollten Sie dies wahrscheinlich explizit angeben. Aber selbst wenn es funktionierte genau das gleiche wie !!userId, es ist nicht klar , ob Sie wollen diese Werte hier falsch zu kommen, oder ob Sie nur Regeln Javascript die Typumwandlung zu prüfen , ist fehlgeschlagen.
Philh
449

!!exprGibt einen booleschen Wert ( trueoder false) zurück, abhängig von der Wahrhaftigkeit des Ausdrucks. Es ist sinnvoller, wenn es für nicht-boolesche Typen verwendet wird. Betrachten Sie diese Beispiele, insbesondere das dritte Beispiel und weiter:

          !!false === false
           !!true === true

              !!0 === false
!!parseInt("foo") === false // NaN is falsy
              !!1 === true
             !!-1 === true  // -1 is truthy

             !!"" === false // empty string is falsy
          !!"foo" === true  // non-empty string is truthy
        !!"false" === true  // ...even if it contains a falsy value

     !!window.foo === false // undefined is falsy
           !!null === false // null is falsy

             !!{} === true  // an (empty) object is truthy
             !![] === true  // an (empty) array is truthy; PHP programmers beware!
Salman A.
quelle
63
Bemerkenswert:!!new Boolean(false) // true
Camilo Martin
43
... aber auch!!Boolean(false) // false
Camilo Martin
97
new Boolean(false)ist ein Objekt und ein Objekt ist wahr, auch wenn es einen falschen Wert enthält!
Salman A
3
Ja ich weiß, aber die Tatsache berücksichtigen , dass die meisten einheimischen Bauer ( String, Number, Date, usw.) auch als Funktionen aufrufbar sein sollen, doch in diesem Fall ist das Ergebnis anders aus !
Camilo Martin
4
@CamiloMartin: nur realisiert , dass new Boolean(false)kehrt ein , objectwährend Boolean(false)die Renditen primitiv false . Hoffe das macht Sinn.
Salman A
155

Tee kochen:

!!ist kein Operator. Es ist die doppelte Verwendung von !- was der logische "Nicht" -Operator ist.


In der Theorie:

! bestimmt die "Wahrheit" dessen, was ein Wert nicht ist:

  • Die Wahrheit ist, dass dies falsenicht der Fall ist true(deshalb !falseergibt sich true)

  • Die Wahrheit ist, dass dies truenicht der Fall ist false(deshalb !trueergibt sich false)


!!bestimmt die „Wahrheit“ von dem, was ein Wert ist nicht nicht:

  • Die Wahrheit ist, dass dies truenicht der Fall ist true (deshalb !!trueergibt sich true)

  • Die Wahrheit ist, dass dies falsenicht der Fall ist false (deshalb !!falseergibt sich false)


Was wir im Vergleich feststellen wollen, ist die "Wahrheit" über den Wert einer Referenz, nicht den Wert der Referenz selbst. Es gibt einen Anwendungsfall, in dem wir die Wahrheit über einen Wert wissen möchten, selbst wenn wir erwarten, dass der Wert false(oder Falsey) ist, oder wenn wir erwarten, dass der Wert nicht typisiert ist boolean.


In der Praxis:

Stellen Sie sich eine übersichtliche Funktion vor, die die Funktionsfunktionalität (und in diesem Fall die Plattformkompatibilität) durch dynamische Typisierung (auch als "Ententypisierung" bezeichnet) erkennt . Wir möchten eine Funktion schreiben, die zurückgibt, truewenn der Browser eines Benutzers das HTML5- <audio>Element unterstützt, aber wir möchten nicht, dass die Funktion einen Fehler <audio>auslöst, wenn sie nicht definiert ist. und wir wollen nicht verwenden try ... catch, um mögliche Fehler zu behandeln (weil sie grob sind); Außerdem möchten wir keine Prüfung innerhalb der Funktion verwenden, die nicht immer die Wahrheit über die Funktion preisgibt (z. B. document.createElement('audio')wird immer noch ein Element namens aufgerufen, <audio>auch wenn HTML5 <audio>nicht unterstützt wird).


Hier sind die drei Ansätze:

// this won't tell us anything about HTML5 `<audio>` as a feature
var foo = function(tag, atr) { return document.createElement(tag)[atr]; }

// this won't return true if the feature is detected (although it works just fine)
var bar = function(tag, atr) { return !document.createElement(tag)[atr]; }

// this is the concise, feature-detecting solution we want
var baz = function(tag, atr) { return !!document.createElement(tag)[atr]; }

foo('audio', 'preload'); // returns "auto"
bar('audio', 'preload'); // returns false
baz('audio', 'preload'); // returns true

Jede Funktion akzeptiert ein Argument für a <tag>und a, attributenach dem gesucht werden soll, gibt jedoch unterschiedliche Werte zurück, je nachdem, was die Vergleiche bestimmen.

Aber warte, da ist noch mehr!

Einige von euch wahrscheinlich in diesem speziellen Beispiel bemerkt , dass man einfach für eine Eigenschaft überprüfen könnten , die leicht mit leistungsfähigere Mittel zur Überprüfung , ob das betreffende Objekt hat eine Eigenschaft. Es gibt zwei Möglichkeiten, dies zu tun:

// the native `hasOwnProperty` method
var qux = function(tag, atr) { return document.createElement(tag).hasOwnProperty(atr); }

// the `in` operator
var quux = function(tag, atr) { return atr in document.createElement(tag); }

qux('audio', 'preload');  // returns true
quux('audio', 'preload'); // returns true

Wir schweifen ab ...

So selten diese Situationen auch sein mögen, es kann einige Szenarien geben, in denen das prägnanteste, performanteste und daher am meisten bevorzugte Mittel zum Abrufen truevon einem nicht-booleschen, möglicherweise undefinierten Wert tatsächlich die Verwendung ist !!. Hoffentlich klärt das lächerlich auf.

Benny
quelle
1
total geniale Antwort, aber ich sehe den Nutzen des !! konstruieren. Da eine if()Anweisung den Ausdruck bereits in einen Booleschen Wert umwandelt, ist das explizite Umwandeln des Rückgabewerts einer Testfunktion in einen Booleschen Wert überflüssig - da "Wahrhaftigkeit" === wahr ist, soweit eine if()Anweisung dies zulässt . Oder fehlt mir ein Szenario, in dem Sie einen wahrheitsgemäßen Ausdruck benötigen, um tatsächlich boolesch zu sein true?
Tom Auger
1
@ TomAuger- if()Anweisungen wandeln Boolesche Werte gegen Falsey-Werte um, sagen jedoch, dass Sie tatsächlich ein Boolesches Flag für ein Objekt setzen möchten - es wird nicht wie eine if()Anweisung gewirkt. Zum Beispiel object.hasTheThing = !!castTheReturnValToBoolNoMatterWhat()würde entweder trueoder falseanstelle des realen Rückgabewerts gesetzt. Ein anderes Beispiel ist vielleicht, dass alle Administratoren idvon 0und Nicht-Administratoren von id 1oder höher sind. Um herauszufinden, trueob jemand kein Administrator ist, können Sie dies tun person.isNotAdmin = !!admin.id. Nur wenige Anwendungsfälle, aber es ist prägnant, wenn es welche gibt.
Benny
103

!!konvertiert den Wert rechts davon in seinen äquivalenten booleschen Wert. (Denken Sie an die Art des "Typ-Castings" des armen Mannes). Seine Absicht ist in der Regel an die Leser zu vermitteln , dass der Code kümmert sich nicht darum , was Wert in der Variablen ist, aber was es ist „Wahrheit“ Wert ist.

Halbmond frisch
quelle
4
Oder im Fall eines booleschen Werts auf der rechten Seite tut es nichts.
Daniel A. White
3
@ Daniel: !kippt den Wert immer noch nach rechts. Bei einem Booleschen !Wert negiert der am weitesten rechts stehende den Wert, während der am weitesten links stehende Wert !ihn erneut negiert. Der Nettoeffekt ist, dass es keine Änderung gibt, aber die meisten Engines generieren Op-Codes für die doppelte Negation.
Crescent Fresh
Aber worum geht es? Wenn ich if(0){...Javascript mache, weiß ich bereits, dass dies falsch ist. Warum ist es besser zu sagen if(!!0){...?
CodyBugstein
Der Punkt ist für Variablen, deren Inhalt Sie möglicherweise nicht kennen. Wenn es sich um eine Ganzzahl oder eine Zeichenfolge, ein Objekt oder eine Null, eine undefinierte usw. handeln kann. Dies ist eine einfache Möglichkeit, die Existenz zu testen.
mix3d
71

!!fooWendet den unären nicht-Operator zweimal an und wird zum Umwandeln in einen booleschen Typ verwendet, ähnlich wie bei der Verwendung von unary plus +foozum Umwandeln in eine Zahl und zum Verketten einer leeren Zeichenfolge ''+foozum Umwandeln in einen String.

Anstelle dieser Hacks können Sie auch die Konstruktorfunktionen verwenden, die den primitiven Typen entsprechen ( ohne verwenden new), um Werte explizit umzuwandeln, d. H.

Boolean(foo) === !!foo
Number(foo)  === +foo
String(foo)  === ''+foo
Christoph
quelle
Aber dann können Sie auf Probleme mit instanceof stoßen. neue boolesche (1) Instanz von Objekt -> wahr !! 1 Instanz von Objekt -> falsch
Seamus
13
Nein, Sie können nicht: Beachten Sie, dass die Konstruktorfunktionen ohne new- wie in meiner Antwort ausdrücklich erwähnt
Christoph
2
Fantastisch! Dies ist nützlich für einen kleinen Hack, wenn Sie Zeichenfolgen mit "0" als falsch anstatt als wahr bewerten müssen. (dh beim Lesen von Werten aus Auswahlen, da diese als Zeichenfolge gelesen werden). Wenn Sie also "0" als negativ (Boolean false) betrachten möchten, x="0"tun Sie asuming do do: Dies x=!!+x; //falseist dasselbe wie Boolean(Number(x))Number (oder + x) konvertiert die Zeichenfolge "0" in 0, die DOED in false auswertet, und dann Boolean (!! x) wandelt es direkt in einen Booleschen Wert um. Kinderleicht!
DiegoDD
2
@DiegoDD warum würdest du !!+xvs wählen x !== "0"?
Placeybordeaux
@placeybordeaux, weil Sie beispielsweise den Wert konvertieren und einer anderen Variablen zuweisen möchten, unabhängig davon, ob Sie ihn mit etwas anderem vergleichen möchten oder nicht.
DiegoDD
67

So viele Antworten machen die halbe Arbeit. Ja, !!Xkönnte als "die Wahrhaftigkeit von X [dargestellt als Boolescher Wert]" gelesen werden. Aber !!ist praktisch nicht so wichtig, um herauszufinden, ob eine einzelne Variable wahr oder falsch ist (oder auch wenn viele Variablen wahr sind). !!myVar === trueist das gleiche wie gerade myVar. Der Vergleich !!Xmit einem "echten" Booleschen Wert ist nicht wirklich nützlich.

Was Sie damit gewinnen, !!ist die Fähigkeit, die Richtigkeit mehrerer Variablen gegeneinander zu prüfen auf wiederholbare, standardisierte (und JSLint-freundliche) Weise .

Einfach gießen :(

Das ist...

  • 0 === falseist false.
  • !!0 === falseist true.

Das obige ist nicht so nützlich. if (!0)gibt Ihnen die gleichen Ergebnisse wie if (!!0 === false). Ich kann mir keinen guten Fall vorstellen, um eine Variable in einen Booleschen Wert umzuwandeln und dann mit einem "wahren" Booleschen Wert zu vergleichen.

Siehe "== und! =" Aus den Anweisungen von JSLint (Hinweis: Crockford verschiebt seine Website ein wenig; dieser Link kann irgendwann sterben) für ein wenig warum:

Die Operatoren == und! = Geben vor dem Vergleich Zwang ein. Dies ist schlecht, da dadurch '\ t \ r \ n' == 0 wahr wird. Dies kann Typfehler maskieren. JSLint kann nicht zuverlässig feststellen, ob == korrekt verwendet wird. Daher ist es am besten, == und! = Überhaupt nicht zu verwenden und stattdessen immer die zuverlässigeren Operatoren === und! == Zu verwenden.

Wenn Sie sich nur darum kümmern, dass ein Wert wahr oder falsch ist, verwenden Sie die Kurzform. Anstatt
(foo != 0)

Sag nur
(foo)

und statt
(foo == 0)

sagen
(!foo)

Beachten Sie, dass es einige nicht intuitive Fälle gibt, in denen ein Boolescher Wert in eine Zahl umgewandelt wird ( truein 1und falsenach 0), wenn ein Boolescher Wert mit einer Zahl verglichen wird. In diesem Fall !!könnte geistig nützlich sein. Obwohl wieder, diese Fälle , in denen Sie ein nicht-boolean zu einem harten typisierte boolean sind zu vergleichen, das ist, imo, ein schwerwiegender Fehler. if (-1)ist immer noch der Weg hierher.

╔═══════════════════════════════════════╦═══════════════════╦═══════════╗
               Original                    Equivalent       Result   
╠═══════════════════════════════════════╬═══════════════════╬═══════════╣
 if (-1 == true) console.log("spam")    if (-1 == 1)       undefined 
 if (-1 == false) console.log("spam")   if (-1 == 0)       undefined 
   Order doesn't matter...                                           
 if (true == -1) console.log("spam")    if (1 == -1)       undefined 
╠═══════════════════════════════════════╬═══════════════════╬═══════════╣
 if (!!-1 == true) console.log("spam")  if (true == true)  spam       better
╠═══════════════════════════════════════╬═══════════════════╬═══════════╣
 if (-1) console.log("spam")            if (truthy)        spam       still best
╚═══════════════════════════════════════╩═══════════════════╩═══════════╝

Und je nach Motor wird es noch verrückter. WScript zum Beispiel gewinnt den Preis.

function test()
{
    return (1 === 1);
}
WScript.echo(test());

Aufgrund eines historischen Windows-Jives wird -1 in einem Meldungsfeld ausgegeben! Versuchen Sie es in einer cmd.exe-Eingabeaufforderung und sehen Sie! Aber WScript.echo(-1 == test())gibt Ihnen immer noch 0 oder WScript false. Schau weg. Es ist schrecklich.

Wahrhaftigkeit vergleichen :)

Aber was ist, wenn ich zwei Werte habe, die ich auf gleiche Wahrheit / Falschheit prüfen muss?

Stellen Sie sich vor, wir hätten myVar1 = 0;und myVar2 = undefined;.

  • myVar1 === myVar2ist 0 === undefinedund ist offensichtlich falsch.
  • !!myVar1 === !!myVar2ist !!0 === !!undefinedund ist wahr! Gleiche Wahrhaftigkeit! (In diesem Fall haben beide "eine Wahrheit der Falschheit".)

Der einzige Ort, an dem Sie wirklich "boolesche Cast-Variablen" verwenden müssten, wäre, wenn Sie eine Situation hätten, in der Sie prüfen, ob beide Variablen die gleiche Wahrhaftigkeit haben, oder? Das heißt, verwenden Sie , wenn Sie sehen müssen, ob zwei Vars beide wahr oder beide falsch (oder nicht) sind, dh von gleicher (oder nicht) Wahrhaftigkeit .!!

Ich kann mir keinen großartigen, nicht erfundenen Anwendungsfall für diese Nebenhand vorstellen. Vielleicht haben Sie Felder in einem Formular "verknüpft"?

if (!!customerInput.spouseName !== !!customerInput.spouseAge ) {
    errorObjects.spouse = "Please either enter a valid name AND age " 
        + "for your spouse or leave all spouse fields blank.";
}

Wenn Sie also eine Wahrheit für beide oder eine Falschheit für den Namen und das Alter des Ehepartners haben, können Sie fortfahren. Andernfalls haben Sie nur ein Feld mit einem Wert (oder einer sehr früh arrangierten Ehe) und müssen einen zusätzlichen Fehler in Ihrer errorObjectsSammlung erstellen .


BEARBEITEN 24. Oktober 2017, 6. Februar 19:

Bibliotheken von Drittanbietern, die explizite boolesche Werte erwarten

Hier ist ein interessanter Fall ... !!kann nützlich sein, wenn Bibliotheken von Drittanbietern explizite boolesche Werte erwarten.

Zum Beispiel hat False in JSX (React) eine besondere Bedeutung , die nicht durch einfache Falschheit ausgelöst wird. Wenn Sie versucht haben, in JSX Folgendes zurückzugeben, erwarten Sie ein int in messageCount...

{messageCount && <div>You have messages!</div>}

... Sie könnten überrascht sein, 0wenn React a rendert, wenn Sie keine Nachrichten haben. Sie müssen explizit false zurückgeben, damit JSX nicht gerendert wird. Die obige Anweisung gibt zurück 0, die JSX gerne wiedergibt, wie es sollte. Es kann nicht sagen, dass Sie nicht hatten Count: {messageCount && <div>Get your count to zero!</div>}(oder etwas weniger erfunden).

  • Ein Update beinhaltet die bangbang, die nötigt 0in !!0, das ist false:
    {!!messageCount && <div>You have messages!</div>}

  • In den JSX-Dokumenten wird empfohlen, expliziter zu sein, selbstkommentierenden Code zu schreiben und einen Vergleich zu verwenden, um einen Booleschen Wert zu erzwingen.
    {messageCount > 0 && <div>You have messages!</div>}

  • Ich fühle mich wohler mit Falschheit selbst mit einem ternären -
    {messageCount ? <div>You have messages!</div> : false}

Gleiches Angebot in Typescript: Wenn Sie eine Funktion haben, die einen Booleschen Wert zurückgibt (oder einer booleschen Variablen einen Wert zuweisen), können Sie [normalerweise] keinen Booleschen-y-Wert zurückgeben / zuweisen. Es muss ein stark typisierter Boolescher Wert sein. Dies bedeutet, dass iffmyObject , wenn es stark typisiert ist , return !myObject;für eine Funktion funktioniert, die einen Booleschen Wert zurückgibt, dies jedoch return myObject;nicht tut. Sie müssen return !!myObjectden Erwartungen von Typescript entsprechen.

Die Ausnahme für Typescript? Wenn dies der Fall myObjectwar any, befinden Sie sich wieder im Wilden Westen von JavaScript und können es ohne zurückgeben !!, auch wenn Ihr Rückgabetyp ein Boolescher Wert ist.

Beachten Sie, dass dies JSX- und Typescript-Konventionen sind, die JavaScript nicht eigen sind .

Aber wenn Sie seltsame 0s in Ihrem gerenderten JSX sehen, denken Sie an lockeres Falsy-Management.

Ruffin
quelle
Gute Erklärung. Also würdest du das sagen !! ist in diesem Beispiel zur Erkennung von Worker-Funktionen nicht unbedingt erforderlich ? if (!!window.Worker)
jk7
2
Nein, du würdest es nicht brauchen. Wahrhaftigkeit und true"extern" funktionieren in einem genau gleich if. Ich versuche es weiter, aber ich kann mir keinen Grund vorstellen, die Wahrhaftigkeit lieber auf einen booleschen Wert außerhalb des oben genannten verschlungenen Falles "Wahrheiten vergleichen" zu übertragen, mit Ausnahme der Lesbarkeit, wenn Sie den Wert später wiederverwenden, wie im qBeispiel der Bibliothek . Aber selbst dann ist es eine Abkürzung mit Informationsverlust, und ich würde behaupten, dass Sie jedes Mal besser dran sind, die Wahrhaftigkeit zu bewerten.
Ruffin
Reagieren ist der Hauptgrund, warum wir angefangen haben, das !! Muster, aber es ist eine sehr bequeme und wiederholbare Sache. Ich muss mich nur um die Wahrhaftigkeit oder Falschheit von etwas kümmern, nicht um den zugrunde liegenden Typ.
Downvotes ohne Kommentare machen es schwierig, auf Ihr Anliegen einzugehen! Lassen Sie mich wissen, was schlecht aussieht, und ich werde mich gerne darum kümmern.
Ruffin
55

Es ist nur der logische NOT-Operator, zweimal - er wird verwendet, um etwas in Boolesche Werte umzuwandeln, z.

true === !!10

false === !!0
Greg
quelle
3
Warum um alles in der Welt würdest du das tun? Verwenden Sie die! Operator, der in einen Booleschen Wert konvertiert werden soll. Verwenden Sie dann ===, um den Typ zu vergleichen. Akzeptiere einfach, dass du keine Typensicherheit hast und mache val> 0 oder so.
Darren Clark
43
@ Darren: Er vergleicht keine Typen; Er sagt Ihnen, was die Ergebnisse sind, indem er Aussagen in seine Antwort schreibt.
Leichtigkeitsrennen im Orbit
32

Es konvertiert das Suffix in einen Booleschen Wert.

Paul McMillan
quelle
26

Es ist eine doppelte notOperation. Der erste !konvertiert den Wert in einen Booleschen Wert und invertiert seinen logischen Wert. Der zweite !invertiert den logischen Wert zurück.

Bill die Eidechse
quelle
26

Es scheint, dass der !!Operator zu einer doppelten Negation führt.

var foo = "Hello World!";

!foo // Result: false
!!foo // Result: true
Steve Harrison
quelle
23

Es simuliert das Verhalten der Boolean()Gießfunktion. Der erste NOTgibt einen booleschen Wert zurück, unabhängig davon, welcher Operand angegeben ist. Der zweite NOTnegiert diesen BooleanWert und gibt so den trueBooleschen Wert einer Variablen an. Das Endergebnis entspricht der Verwendung der Boolean()Funktion für einen Wert.

Prakash
quelle
20

! ist "boolean not", was im Wesentlichen den Wert von "enable" gegenüber seinem booleschen Gegenteil typisiert. Der Zweite ! dreht diesen Wert um. Bedeutet !!enablealso "nicht nicht aktivieren" und gibt Ihnen den Wert enableeines Booleschen Werts .

Annika Backstrom
quelle
18

Erwähnenswert ist meiner Meinung nach, dass eine Bedingung in Kombination mit logischem UND / ODER keinen booleschen Wert zurückgibt, sondern den letzten Erfolg oder den ersten Fehler bei && und den ersten Erfolg oder den letzten Fehler bei || der Zustandskette.

res = (1 && 2); // res is 2
res = (true && alert) // res is function alert()
res = ('foo' || alert) // res is 'foo'

Um die Bedingung in ein echtes boolesches Literal umzuwandeln, können wir die doppelte Negation verwenden:

res = !!(1 && 2); // res is true
res = !!(true && alert) // res is true
res = !!('foo' || alert) // res is true
GreQ
quelle
17

!!Es verwendet die NOTOperation zweimal zusammen, !konvertiert den Wert in a booleanund kehrt ihn um. Hier ist ein einfaches Beispiel, um zu sehen, wie es !!funktioniert:

Zuerst haben Sie den Ort, den Sie haben:

var zero = 0;

Dann !0wird es in einen Booleschen Wert konvertiert und in ausgewertet true, da 0 ist falsy. Sie erhalten also den umgekehrten Wert und werden in einen Booleschen Wert konvertiert, sodass er in ausgewertet wird true.

!zero; //true

aber wir wollen nicht die umgekehrte boolesche Version des Wertes, also können wir sie wieder umkehren, um unser Ergebnis zu erhalten! Deshalb verwenden wir einen anderen !.

!!Stellen Sie im Grunde sicher, dass der Wert, den wir erhalten, boolesch ist, nicht falsch, wahr oder string etc ...

Es ist also so, als würde man eine BooleanFunktion in Javascript verwenden, aber eine einfache und kürzere Möglichkeit, einen Wert in einen Booleschen Wert umzuwandeln:

var zero = 0;
!!zero; //false
Alireza
quelle
15

Das !!Konstrukt ist eine einfache Möglichkeit, einen JavaScript-Ausdruck in ein boolesches Äquivalent umzuwandeln.

Zum Beispiel: !!"he shot me down" === trueund !!0 === false.

Navin Rauniyar
quelle
2
Sehr nah an der wichtigen Unterscheidung. Der Schlüssel ist, dass 0 === falsedas falsch und !!0 === falsewahr ist.
Ruffin
14

Es ist kein einzelner Operator, es sind zwei. Es entspricht dem Folgenden und ist eine schnelle Möglichkeit, einen Wert in einen Booleschen Wert umzuwandeln.

val.enabled = !(!enable);
Justin Johnson
quelle
10

Ich vermute, dies ist ein Überbleibsel aus C ++, bei dem die Leute das überschreiben! Operator, aber nicht der Bool-Operator.

Um in diesem Fall eine negative (oder positive) Antwort zu erhalten, müssten Sie zuerst die! Operator, um einen Booleschen Wert zu erhalten, aber wenn Sie den positiven Fall überprüfen möchten, würde verwenden !!.

Darren Clark
quelle
10

Der ifund whileAussagen und die ?Betreiber Werte Verwendung Wahrheit zu bestimmen , welchen Zweig des Code auszuführen. Zum Beispiel sind Null- und NaN-Zahlen und die leere Zeichenfolge falsch, aber andere Zahlen und Zeichenfolgen sind wahr. Objekte sind wahr, aber der undefinierte Wert und nullbeide sind falsch.

Der Doppel-Negationsoperator !!berechnet den Wahrheitswert eines Wertes. Es sind eigentlich zwei Operatoren, wo !!xbedeutet !(!x)und verhält sich wie folgt:

  • Wenn xein falscher Wert !xist true, ist und !!xist false.
  • Wenn xist ein wahrer Wert, !xist falseund !!xist true.

Wenn auf der obersten Ebene eines Booleschen Kontext verwendet ( if, whileoder ?), die !!ist Operator behaviorally ein no-op. Zum Beispiel if (x)und if (!!x)bedeuten das Gleiche.

Praktische Anwendungen

Es hat jedoch mehrere praktische Anwendungen.

Eine Verwendung besteht darin, ein Objekt verlustbehaftet auf seinen Wahrheitswert zu komprimieren, sodass Ihr Code keinen Verweis auf ein großes Objekt enthält und es am Leben erhält. Wenn Sie !!some_big_objecteiner Variablen zuweisen , anstatt some_big_objectsie für den Garbage Collector loszulassen. Dies ist nützlich für Fälle, in denen entweder ein Objekt oder ein falscher Wert wie nullder undefinierte Wert wie die Erkennung von Browserfunktionen erzeugt wird.

Eine andere Verwendung, die ich in einer Antwort über den entsprechenden !!Operator von C erwähnt habe , sind "Flusen" -Tools, die nach allgemeinen Tippfehlern und Druckdiagnosen suchen. Beispielsweise führen sowohl in C als auch in JavaScript einige häufig vorkommende Tippfehler für Boolesche Operationen zu anderen Verhaltensweisen, deren Ausgabe nicht ganz so Boolesch ist:

  • if (a = b)ist die Zuordnung gefolgt von der Verwendung des Wahrheitswertes von b; if (a == b)ist ein Gleichheitsvergleich.
  • if (a & b)ist ein bitweises UND; if (a && b)ist ein logisches UND. 2 & 5ist 0(ein falscher Wert); 2 && 5ist wahr.

Der !!Bediener versichert dem Flusenwerkzeug, dass das, was Sie geschrieben haben, das ist, was Sie gemeint haben: Führen Sie diese Operation aus und nehmen Sie dann den Wahrheitswert des Ergebnisses.

Eine dritte Verwendung besteht darin, logisches XOR und logisches XNOR zu erzeugen. Führt sowohl in C als auch in JavaScript a && bein logisches UND aus (wahr, wenn beide Seiten wahr sind) und a & bein bitweises UND. a || bführt ein logisches ODER aus (wahr, wenn mindestens eines wahr ist) und a | bführt ein bitweises ODER durch. Es gibt ein bitweises XOR (exklusives ODER) als a ^ b, aber es gibt keinen eingebauten Operator für logisches XOR (wahr, wenn genau eine Seite wahr ist). Möglicherweise möchten Sie dem Benutzer beispielsweise erlauben, Text in genau eines von zwei Feldern einzugeben. Was Sie tun können, ist, jeden in einen Wahrheitswert umzuwandeln und zu vergleichen : !!x !== !!y.

Damian Yerrick
quelle
8

Doppelte boolesche Negation. Wird oft verwendet, um zu überprüfen, ob der Wert nicht undefiniert ist.

Sergey Ilinsky
quelle
8

Tonnenweise gute Antworten hier, aber wenn Sie so weit gelesen haben, hat mir das geholfen, es zu verstehen. Öffnen Sie die Konsole in Chrome (usw.) und geben Sie Folgendes ein:

!(!(1))
!(!(0))
!(!('truthy')) 
!(!(null))
!(!(''))
!(!(undefined))
!(!(new Object())
!(!({}))
woo = 'hoo'
!(!(woo))
...etc, etc, until the light goes on ;)

Natürlich sind diese alle gleichbedeutend mit bloßem Tippen !! someThing, aber die hinzugefügten Klammern könnten helfen, es verständlicher zu machen.

Warren Davis
quelle
8

!!x ist eine Abkürzung für Boolean(x)

Der erste Knall zwingt den js-Motor zum Laufen Boolean(x), hat aber auch den Nebeneffekt, dass der Wert invertiert wird. Der zweite Knall macht also den Nebeneffekt rückgängig.

Greg Gum
quelle
8

Es zwingt alle Dinge zum Booleschen.

Zum Beispiel:

console.log(undefined); // -> undefined
console.log(!undefined); // -> true
console.log(!!undefined); // -> false

console.log('abc'); // -> abc
console.log(!'abc'); // -> false
console.log(!!'abc'); // -> true

console.log(0 === false); // -> undefined
console.log(!0 === false); // -> false
console.log(!!0 === false); // -> true
Khuong
quelle
7

Diese Frage wurde ziemlich gründlich beantwortet, aber ich möchte eine Antwort hinzufügen, von der ich hoffe, dass sie so einfach wie möglich ist und die Bedeutung von !! so einfach zu erfassen wie möglich.

Da Javascript sogenannte "truey" - und "falsey" -Werte hat, gibt es Ausdrücke, die bei Auswertung in anderen Ausdrücken zu einer wahren oder falschen Bedingung führen, obwohl der untersuchte Wert oder Ausdruck nicht tatsächlich trueoder falsch ist false.

Zum Beispiel:

if (document.getElementById('myElement')) {
    // code block
}

Wenn dieses Element tatsächlich vorhanden ist, wird der Ausdruck als wahr ausgewertet und der Codeblock ausgeführt.

Jedoch:

if (document.getElementById('myElement') == true) {
    // code block
}

... führt NICHT zu einer echten Bedingung, und der Codeblock wird nicht ausgeführt, selbst wenn das Element vorhanden ist.

Warum? Weil document.getElementById()es sich um einen "wahrheitsgemäßen" Ausdruck handelt, der in dieser if()Aussage als wahr ausgewertet wird , aber kein tatsächlicher boolescher Wert von ist true.

Das doppelte "nicht" ist in diesem Fall ganz einfach. Es sind einfach zwei notSekunden hintereinander.

Der erste "invertiert" einfach den Wahrheits- oder False-Wert, was zu einem tatsächlichen Booleschen Typ führt, und der zweite "invertiert" ihn wieder in seinen ursprünglichen Zustand, aber jetzt in einen tatsächlichen Booleschen Wert. Auf diese Weise haben Sie Konsistenz:

if (!!document.getElementById('myElement')) {}

und

if (!!document.getElementById('myElement') == true) {}

wird BEIDE wie erwartet true zurückgeben.

Kirby L. Wallace
quelle
7

Ich wollte das nur hinzufügen

if(variableThing){
  // do something
}

ist das gleiche wie

if(!!variableThing){
  // do something
}

Dies kann jedoch ein Problem sein, wenn etwas undefiniert ist.

// a === undefined, b is an empty object (eg. b.asdf === undefined)
var a, b = {};

// Both of these give error a.foo is not defined etc.
// you'd see the same behavior for !!a.foo and !!b.foo.bar

a.foo 
b.foo.bar

// This works -- these return undefined

a && a.foo
b.foo && b.foo.bar
b && b.foo && b.foo.bar

Der Trick dabei ist, dass die Kette von &&s den ersten gefundenen Falsey-Wert zurückgibt - und dieser kann einer if-Anweisung usw. zugeführt werden. Wenn also b.foo undefiniert ist, gibt sie undefiniert zurück und überspringt denb.foo.bar Anweisung, und wir erhalten no Error.

Die obigen Werte geben undefiniert zurück, aber wenn Sie eine leere Zeichenfolge haben, false, null, 0, undefined, werden diese Werte zurückgegeben und sobald wir sie in der Kette finden - []und{} beide sind "wahr" und wir werden den sogenannten " && Kette "zum nächsten Wert rechts.

PS Eine andere Möglichkeit, dasselbe zu tun, besteht darin (b || {}).foo, dass wenn b undefiniert ist b || {}, dies der Fall {}ist und Sie auf einen Wert in einem leeren Objekt zugreifen (kein Fehler), anstatt zu versuchen, auf einen Wert innerhalb von "undefiniert" zuzugreifen (verursacht einen Fehler) ). Also (b || {}).fooist das gleiche wie b && b.foound ((b || {}).foo || {}).barist das gleiche wie b && b.foo && b.foo.bar.

Ryan Taylor
quelle
guter Punkt - änderte meine Antwort. Es passiert nur auf einem Objekt, wenn es drei Ebenen tief verschachtelt ist, denn wie Sie sagten, ({}).anythingwird es gebenundefined
Ryan Taylor
5

Nachdem ich all diese großartigen Antworten gesehen habe, möchte ich einen weiteren Grund für die Verwendung hinzufügen !!. Derzeit arbeite ich in Angular 2-4 (TypeScript) und möchte einen Booleschen Wert zurückgeben, falsewenn mein Benutzer nicht authentifiziert ist. Wenn er nicht authentifiziert ist, wäre die Token-Zeichenfolge nulloder "". Ich kann dies mit dem nächsten Codeblock tun:

public isAuthenticated(): boolean {
   return !!this.getToken();
}
Wouter Vanherck
quelle
4

Hier ist ein Stück Code aus eckigen js

var requestAnimationFrame = $window.requestAnimationFrame ||
                                $window.webkitRequestAnimationFrame ||
                                $window.mozRequestAnimationFrame;

 var rafSupported = !!requestAnimationFrame;

Sie beabsichtigen, rafSupported basierend auf der Verfügbarkeit der Funktion in requestAnimationFrame auf true oder false zu setzen

Dies kann erreicht werden, indem im Allgemeinen auf folgende Weise geprüft wird:

if(typeof  requestAnimationFrame === 'function')
rafSupported =true;
else
rafSupported =false;

Der kurze Weg könnte sein !!

rafSupported = !!requestAnimationFrame ;

Wenn also requestAnimationFrame eine Funktion zugewiesen wurde, wäre! requestAnimationFrame falsch und eine weitere! davon wäre wahr

Wenn requestAnimationFrame als undefiniert eingestuft würde, wäre! requestAnimationFrame wahr und noch einer! davon wäre falsch

JeevanReddy Avanaganti
quelle
3

Einige Operatoren in JavaScript führen implizite Typkonvertierungen durch und werden manchmal für die Typkonvertierung verwendet.

Der unäre !Operator konvertiert seinen Operanden in einen Booleschen Wert und negiert ihn.

Diese Tatsache führt zu der folgenden Redewendung, die Sie in Ihrem Quellcode sehen können:

!!x // Same as Boolean(x). Note double exclamation mark
GibboK
quelle
3

Verwenden Sie den logischen Nicht-Operator zweimal
, was bedeutet! True = false
und !! true = true

Abhay Dixit
quelle
3

Gibt den booleschen Wert einer Variablen zurück.

Stattdessen kann BooleanKlasse verwendet werden.

(Bitte Codebeschreibungen lesen)

var X = "test"; // X value is "test" as a String value
var booleanX = !!X // booleanX is `true` as a Boolean value beacuse non-empty strings evaluates as `true` in boolean
var whatIsXValueInBoolean = Boolean(X) // whatIsXValueInBoolean is `true` again
console.log(Boolean(X) === !!X) // writes `true`

Nämlich Boolean(X) = !!Xim Einsatz.

Bitte überprüfen Sie den Code-Ausschnitt unten

let a = 0
console.log("a: ", a) // writes a value in its kind
console.log("!a: ", !a) // writes '0 is NOT true in boolean' value as boolean - So that's true.In boolean 0 means false and 1 means true.
console.log("!!a: ", !!a) // writes 0 value in boolean. 0 means false.
console.log("Boolean(a): ", Boolean(a)) // equals to `!!a`
console.log("\n") // newline

a = 1
console.log("a: ", a)
console.log("!a: ", !a)
console.log("!!a: ", !!a) // writes 1 value in boolean
console.log("\n") // newline

a = ""
console.log("a: ", a)
console.log("!a: ", !a) // writes '"" is NOT true in boolean' value as boolean - So that's true.In boolean empty strings, null and undefined values mean false and if there is a string it means true.
console.log("!!a: ", !!a) // writes "" value in boolean
console.log("\n") // newline

a = "test"
console.log("a: ", a) // writes a value in its kind
console.log("!a: ", !a)
console.log("!!a: ", !!a) // writes "test" value in boolean

console.log("Boolean(a) === !!a: ", Boolean(a) === !!a) // writes true

efkan
quelle