Frage Was ist der !! (nicht nicht) operator in JavaScript?


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

Der Kontext, in dem ich das gesehen habe, war

this.vertical = vertical !== undefined ? !!vertical : this.vertical;

2316
2018-04-24 08:13


Ursprung


Antworten:


Zwänge oObject zu Boolean. Wenn es falsch war (z. B. 0, null, undefinedusw.), wird es sein false, Andernfalls, true.

!oObject  //Inverted boolean
!!oObject //Non inverted boolean so true boolean representation

Damit !! ist kein Operator, es ist nur der ! Betreiber zweimal.

Real World Beispiel "Test IE version":

let isIE8 = false;  
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 null  

aber wenn du ⇒

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

2068
2018-04-24 08:18



Es ist eine schrecklich obskure Art, eine Typumwandlung durchzuführen.

! ist NICHT. Damit !true ist false, und !false ist true. !0 ist true, und !1 ist false.

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

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

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

// And finally, much easier to understand:
val.enabled = (userId != 0);

729
2017-09-10 17:28



!!expr liefert einen Booleschen Wert (true oder false) abhängig von Wahrheit des Ausdrucks. Es macht mehr Sinn, wenn es auf nicht-booleschen Typen verwendet wird. Betrachten Sie diese Beispiele, besonders das 3. 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!

372
2018-05-15 09:06



Tee brauen:

!! ist kein Operator. Es ist die Doppelnutzung von ! - Das ist der logische "Nicht" -Operator.


In der Theorie:

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

  • Die Wahrheit ist das false ist nicht true (deshalb !false Ergebnisse im true)

  • Die Wahrheit ist das true ist nicht false (deshalb !true Ergebnisse im false)


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

  • Die Wahrheit ist das true ist nicht nicht  true (deshalb !!true Ergebnisse in true)

  • Die Wahrheit ist das false ist nicht nicht  false (deshalb !!false Ergebnisse in false)


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


In der Praxis:

Betrachten Sie eine prägnante Funktion, die Feature-Funktionalität (und in diesem Fall Plattform-Kompatibilität) über erkennt dynamische Eingabe (aka "Ente tippen"). Wir wollen eine Funktion schreiben, die zurückkehrt true wenn der Browser eines Benutzers HTML5 unterstützt <audio> Element, aber wir wollen nicht, dass die Funktion einen Fehler ausgibt <audio> ist nicht definiert; und wir wollen nicht verwenden try ... catch um mögliche Fehler zu behandeln (weil sie grob sind); und auch Wir möchten keinen Check innerhalb der Funktion verwenden, der nicht immer die Wahrheit über das Feature enthüllt (z. B. document.createElement('audio') erstellt immer noch ein Element namens <audio> auch wenn HTML5 <audio> wird nicht unterstützt).


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 ein attribute zu suchen, aber sie geben jeweils unterschiedliche Werte zurück, basierend auf dem, was die Vergleiche bestimmen.

Aber warte, da ist mehr!

Einige von euch haben wahrscheinlich bemerkt, dass man in diesem speziellen Beispiel einfach nach einer Eigenschaft suchen kann, die etwas verwendet leistungsfähiger Mittel zur Überprüfung ob das Objekt in Frage kommt hat Ein Besitz. Dazu gibt es zwei Möglichkeiten:

// 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 ...

Wie selten diese Situationen auch sein mögen, es gibt möglicherweise ein paar Szenarien, in denen die prägnantesten, leistungsfähigsten und damit am meisten bevorzugten Mittel zur Verfügung stehen true aus einem nicht booleschen, möglicherweise undefinierten Wert wird zwar mit verwendet !!. Hoffentlich klärt es sich lächerlich auf.


128
2018-02-22 23:45



!! konvertiert den Wert rechts davon in den entsprechenden booleschen Wert. (Denken Sie an den "Typ-Casting" des armen Mannes). Es ist Absicht In der Regel soll dem Leser vermittelt werden, dass dem Code egal ist Was Wert ist in der Variable, aber was ist es "Wahrheitswert ist.


87
2017-09-10 17:26



!!foo wendet den unären Nicht-Operator zweimal an und wird verwendet, um einen booleschen Typ zu verwenden, der dem von unary plus ähnelt +foo um eine leere Zeichenfolge zu verketten und zu verketten ''+foo in eine Zeichenfolge umwandeln

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

Boolean(foo) === !!foo
Number(foo)  === +foo
String(foo)  === ''+foo

59
2017-09-10 21:15



So viele Antworten machen die halbe Arbeit. Ja, !!X könnte gelesen werden als "die Wahrhaftigkeit von X [dargestellt als Boolean]". Aber !! ist praktisch nicht so wichtig, um herauszufinden, ob eine einzelne Variable truthy oder falsy ist (oder sogar wenn viele Variablen sind). !!myVar === true ist das Gleiche wie nur myVar. Vergleichen !!X zu einem "echten" Booleschen ist nicht wirklich nützlich.

Womit du gewinnst !! ist die Fähigkeit, die Wahrheit mehrerer Variablen zu überprüfen gegen einander in einer wiederholbaren, standardisierten (und JSLint-freundlichen) Art und Weise.

Einfaches Casting :(

Das ist...

  • 0 === false ist false.
  • !!0 === false ist true.

Das oben genannte ist nicht so nützlich. if (!0) gibt Ihnen die gleichen Ergebnisse wie if (!!0 === false). Ich kann mir keinen guten Fall vorstellen, wenn ich eine Variable in einen Booleschen Wert umwandeln und dann mit einem "wahren" booleschen Wert vergleichen würde.

Siehe "== und! =" Von JSLints Anweisungen (Anmerkung: Crockford bewegt seine Seite ein wenig herum; dieser Link wird irgendwann sterben) für ein wenig auf warum:

Die Operatoren == und! = Geben vor dem Vergleich die Bedingung ein. Das ist schlecht, weil es bewirkt, dass '\ t \ r \ n' == 0 wahr ist. Dies kann Fehlertypen maskieren. JSLint kann nicht zuverlässig feststellen, ob == korrekt verwendet wird, daher ist es am besten, == und! = Überhaupt nicht zu verwenden und stattdessen die zuverlässigeren Operatoren === und! == zu verwenden.

Wenn Sie nur darauf achten, dass ein Wert truthy oder falsy ist, dann verwenden Sie die Kurzform. Anstatt von
(foo != 0)

Sag nur
(foo)

und statt
(foo == 0)

sagen
(!foo)

Beachten Sie, dass es einige gibt nicht intuitive Fälle wo ein Boolescher Wert in eine Zahl umgewandelt wird (true wird geworfen 1 und false zu 0) wenn man einen booleschen Wert mit einer Zahl vergleicht. In diesem Fall, !! könnte geistig nützlich sein. Obwohl wieder In diesen Fällen vergleicht man einen nicht-booleschen Wert mit einem hart-typisierten booleschen Wert, was ein schwerwiegender Fehler ist.  if (-1) ist immer noch der Weg hierher zu gehen.

╔═══════════════════════════════════════╦═══════════════════╦═══════════╗
║               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 Motorisierung wird es noch verrückter. WScript zum Beispiel gewinnt den Preis.

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

Durch einige historische Windows Jive, das gibt -1 in einer Nachrichtenbox aus! Probieren Sie es in einer cmd.exe Prompt und sehen Sie! Aber WScript.echo(-1 == test()) gibt Ihnen immer noch 0, oder WScript's false. Schau weg. Es ist scheußlich.

Wahrheit vergleichen :)

Aber was, wenn ich zwei Werte habe, muss ich nach der gleichen Wahrheit / Fälschung suchen?

Tun wir so myVar1 = 0; und myVar2 = undefined;.

  • myVar1 === myVar2 ist 0 === undefined und ist offensichtlich falsch.
  • !!myVar1 === !!myVar2 ist !!0 === !!undefined und ist wahr! Gleiche Wahrheit! (In diesem Fall haben beide eine Wahrhaftigkeit von Falschheit.)

Der einzige Ort, an dem Sie wirklich "Boolean-Cast-Variablen" verwenden müssten, wäre, wenn Sie eine Situation hätten, in der Sie prüfen, ob beide Variablen den gleich Wahrheit, oder? Das ist, benutzen !! wenn Sie sehen müssen, ob zwei Vars sind beide truthy oder beide falsy (oder nicht), das heißt, gleich (oder nicht) Wahrheit.

Ich kann mir dafür keinen großen, nicht erfundenen Anwendungsfall vorstellen. Vielleicht haben Sie Felder in einem Formular "verlinkt"?

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

Also jetzt, wenn Sie eine Truthy für beide haben oder eine Falsy für beide Ehepartner und Alter, können Sie fortfahren. Ansonsten hast du nur ein Feld mit einem Wert (oder eine sehr früh arrangierte Hochzeit) und musst einen zusätzlichen Fehler auf deinem erstellen errorObjects Sammlung.


EDIT 24. Oktober 2017: 

Bibliotheken von Drittanbietern, die explizite boolesche Werte erwarten

Hier ist ein interessanter Fall ... !! könnte nützlich sein, wenn 3rd-Party-Bibliotheken explizite boolesche Werte erwarten.

Zum Beispiel, False in JSX (React) hat eine besondere Bedeutung das ist nicht auf einfache Falschheit ausgelöst. Wenn Sie versucht haben, in Ihrem JSX etwas wie das Folgende zurückzugeben, wird ein int erwartet messageCount...

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

... könnten Sie überrascht sein, dass React rendern a 0 wenn Sie keine Nachrichten haben. Sie müssen explizit false zurückgeben, damit JSX nicht rendern kann. Die obige Aussage kehrt zurück 0, die JSX glücklich darstellt, 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 Fix beinhaltet den Bangbang, der zwingt 0 in !!0, welches ist false:
    {!!messageCount && <div>You have messages!</div>}

  • JSX 'Dokumente schlagen vor, dass Sie expliziter sind, selbstkommenden Code schreiben und einen Vergleich verwenden, um zu einem Boolean zu zwingen.
    {messageCount > 0 && <div>You have messages!</div>}

  • Ich bin bequemer, Falschheit mit einem Ternär umzugehen -
    {messageCount ? <div>You have messages!</div> : false}

Denk daran, dass Dies ist eine JSX-KonventionJavaScript gehört nicht dazu.

Aber wenn du merkwürdig siehst 0s in Ihrem gerenderten JSX, denken Sie lose Falsy-Management.


45
2018-04-29 18:14