Vraag Wat is de !! (niet niet) operator in JavaScript?


Ik zag een code die een operator lijkt te gebruiken die ik niet herken, in de vorm van twee uitroeptekens, zoals zo: !!. Kan iemand me vertellen wat deze operator doet?

De context waarin ik dit zag was,

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

2316
2018-04-24 08:13


oorsprong


antwoorden:


dwingt oObject naar boolean. Als het Falsey was (bijvoorbeeld 0, null, undefined, etc.), zal het zijn falseanders true.

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

Zo !! is geen operator, het is gewoon de ! operator twee keer.

Real World Voorbeeld "Test IE-versie":

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

Als u ⇒

console.log(navigator.userAgent.match(/MSIE 8.0/));  
// returns null  

maar als je ⇒

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

2068
2018-04-24 08:18



Het is een vreselijk obscure manier om een ​​lettertype-conversie uit te voeren.

! is NIET. Zo !true is false, en !false is true. !0 is true, en !1 is false.

Dus u converteert een waarde naar een booleaanse waarde, waarna u deze inverteren en vervolgens opnieuw inverteren.

// 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 retourneert een Booleaanse waarde (true of false) afhankelijk van truthiness van de uitdrukking. Het is logischer als het wordt gebruikt op niet-booleaanse typen. Overweeg deze voorbeelden, met name het derde en volgende voorbeeld:

          !!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



Brouw wat thee:

!! is geen operator. Het is het dubbele gebruik van ! - wat de logische "niet" -operator is.


In theorie:

! bepaalt de "waarheid" van wat een waarde niet is:

  • De waarheid is dat false is niet true (Dat is waarom !false uitslagen in true)

  • De waarheid is dat true is niet false (Dat is waarom !true uitslagen in false)


!! bepaalt de "waarheid" van wat een waarde is niet niet:

  • De waarheid is dat true is niet niet  true (Dat is waarom !!true resulteert in true)

  • De waarheid is dat false is niet niet  false (Dat is waarom !!false resulteert in false)


Wat we in de vergelijking willen bepalen, is de "waarheid" over de waarde van een referentie, niet de waarde van de referentie zelf. Er is een use-case waarbij we de waarheid over een waarde willen weten, zelfs als we verwachten dat de waarde dat is false (of falsey), of als we verwachten dat de waarde niet van het type is boolean.


In praktijk:

Overweeg een beknopte functie die functiefunctionaliteit (en in dit geval platformcompatibiliteit) detecteert via dynamisch typen (ook bekend als "duck typing"). We willen een functie schrijven die terugkeert true als de browser van een gebruiker de HTML5 ondersteunt <audio> element, maar we willen niet dat de functie een fout oplevert als <audio> is niet gedefinieerd; en we willen niet gebruiken try ... catch om mogelijke fouten te behandelen (omdat ze vies zijn); en ook we willen geen controle binnen de functie gebruiken die niet consequent de waarheid over de functie onthult (bijvoorbeeld document.createElement('audio') zal nog steeds een element maken met de naam <audio> zelfs als HTML5 <audio> wordt niet ondersteund).


Hier zijn de drie benaderingen:

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

Elke functie accepteert een argument voor een <tag> en een attribute om te zoeken naar, maar ze retourneren elk verschillende waarden op basis van wat de vergelijkingen bepalen.

Maar wacht, er is meer!

Sommigen van u hebben waarschijnlijk gemerkt dat in dit specifieke voorbeeld eenvoudig een eigenschap kon worden gecontroleerd met een beetje meer performant middelen om te controleren of het betreffende object heeft een eigendom. Er zijn twee manieren om dit te doen:

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

We dwalen af ​​...

Hoe zeldzaam deze situaties ook zijn, er kunnen een paar scenario's bestaan ​​waar de meest beknopte, meest performante en dus meest geprefereerde manier om te krijgen true van een niet-booleaanse, mogelijk ongedefinieerde waarde is inderdaad door te gebruiken !!. Hopelijk ruimt dit het belachelijk op.


128
2018-02-22 23:45



!! converteert de waarde rechts ervan naar de equivalente booleaanse waarde. (Denk aan de manier van arme man van "type-casting"). Haar voornemen is meestal om aan de lezer over te brengen dat de code niets uitmaakt wat waarde zit in de variabele, maar wat het is "waarheid" waarde is.


87
2017-09-10 17:26



!!foo past de operator unary not tweemaal toe en wordt gebruikt om te casten naar een boolean-type dat lijkt op het gebruik van unary plus +foo om naar een nummer te casten en een lege string samen te voegen ''+foo naar een string casten.

In plaats van deze hacks, kunt u ook de constructorfuncties gebruiken die overeenkomen met de primitieve typen (zonder gebruik makend van new) om expliciet waarden te casten, dwz

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

59
2017-09-10 21:15



Zoveel antwoorden die de helft van het werk doen. Ja, !!X zou kunnen worden gelezen als "de waarachtigheid van X [weergegeven als een boolean]". Maar !! is, praktisch gesproken, niet zo belangrijk om uit te zoeken of een enkele variabele (of zelfs als vele variabelen) waar of vals zijn. !!myVar === true is hetzelfde als alleen myVar. Het vergelijken !!X naar een "echte" boolean is niet echt nuttig.

Waarmee je wint !! is de mogelijkheid om de juistheid van meerdere variabelen te controleren tegen elkaar op een herhaalbare, gestandaardiseerde (en JSLint-vriendelijke) manier.

Gewoon gieten :(

Dat is...

  • 0 === false is false.
  • !!0 === false is true.

Het bovenstaande is niet zo handig. if (!0) geeft je dezelfde resultaten als if (!!0 === false). Ik kan geen goed voorbeeld bedenken voor het casten van een variabele naar Boolean en het vervolgens vergelijken met een "echte" boolean.

Zie "== en! =" Van JSLint's aanwijzingen (let op: Crockford verplaatst zijn site een beetje, die link dreigt op een gegeven moment te sterven) voor een beetje over waarom:

De operators == en! = Typen wel dwang voordat ze worden vergeleken. Dit is slecht omdat het zorgt dat '\ t \ r \ n' == 0 waar is. Dit kan typefouten maskeren. JSLint kan niet betrouwbaar bepalen of == correct wordt gebruikt, dus het is het beste om == en! = Helemaal niet te gebruiken en altijd de betrouwbaardere === en! == operatoren te gebruiken.

Als je alleen maar geeft dat een waarde waar of vals is, gebruik dan het korte formulier. In plaats van
(foo != 0)

zeg gewoon
(foo)

en in plaats van
(foo == 0)

zeggen
(!foo)

Merk op dat er enkele zijn niet-intuïtieve gevallen waar een boolean naar een getal wordt gegoten (true is cast to 1 en false naar 0) bij het vergelijken van een boolean naar een getal. In dit geval, !! kan mentaal nuttig zijn. Maar, nogmaals, dit zijn gevallen waarin u een niet-booleaanse naar een harde getypte booleaanse waarde vergelijkt, wat, imo, een ernstige fout is.  if (-1) is nog steeds de manier om hierheen te gaan.

╔═══════════════════════════════════════╦═══════════════════╦═══════════╗
║               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
╚═══════════════════════════════════════╩═══════════════════╩═══════════╝

En het wordt nog gekker afhankelijk van je motor. WScript wint bijvoorbeeld de prijs.

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

Omdat sommige historische Windows jive, dat zal -1 in een berichtenvenster uitvoeren! Probeer het in een cmd.exe prompt en zie! Maar WScript.echo(-1 == test()) geeft nog steeds 0, of WScript's false. Kijk weg. Het is afschuwelijk.

Vergelijking van waarheid :)

Maar wat als ik twee waarden heb, moet ik controleren op dezelfde waarheid / falsi-heid?

Doe alsof we hebben myVar1 = 0; en myVar2 = undefined;.

  • myVar1 === myVar2 is 0 === undefined en is duidelijk niet waar.
  • !!myVar1 === !!myVar2 is !!0 === !!undefined en is waar! Dezelfde waarheid! (In dit geval hebben beide "een waarheidsgetrouwheid van valsheid".)

Dus de enige plaats waar u echt "boolean-cast variabelen" zou moeten gebruiken, zou zijn als u een situatie zou hebben waarin u controleert of beide variabelen de dezelfde waarachtigheid, toch? Dat is, gebruik !! als je wilt zien of twee vars zijn zowel waarachtig als beide vals (of niet), dat wil zeggen, van gelijk (of niet) truthiness.

Ik kan daar geen geweldige, niet-gekunstelde use-case voor bedenken. Misschien hebt u velden "gekoppeld" in een formulier?

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

Dus nu als je een waarheid hebt voor beide of een vals voor zowel de naam van de echtgenoot als de leeftijd, je kunt doorgaan. Anders heb je maar één veld met een waarde (of een heel vroeg gearrangeerd huwelijk) en moet je een extra fout maken op je errorObjects verzameling.


EDIT 24 okt 2017: 

Bibliotheken van derden die expliciete Booleaanse waarden verwachten

Hier is een interessant geval ... !! kan handig zijn als bibliotheken van derden expliciete Booleaanse waarden verwachten.

Bijvoorbeeld, Vals in JSX (React) heeft een speciale betekenis dat is niet getriggerd op eenvoudige valsheid. Als je probeerde iets als het volgende in je JSX terug te sturen, verwachtte je een int in messageCount...

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

... je zou verbaasd zijn om te zien hoe React rendert 0 wanneer je nul berichten hebt. U moet false retourneren voor JSX om niet te renderen. De bovenstaande verklaring retourneert 0, die JSX graag maakt, zoals het hoort. Het kan niet zeggen dat je het niet had Count: {messageCount && <div>Get your count to zero!</div>} (of iets minder gekunsteld).

  • Eén oplossing betreft de bangbang, die dwingt 0 in !!0, dat is false:
    {!!messageCount && <div>You have messages!</div>}

  • JSX 'documenten suggereren dat je explicieter bent, schrijf zelfcommentaarcode en gebruik een vergelijking om een ​​Booleaanse waarde te forceren.
    {messageCount > 0 && <div>You have messages!</div>}

  • Ik ben comfortabeler in het hanteren van valsheid mezelf met een ternair -
    {messageCount ? <div>You have messages!</div> : false}

Onthoud dat deze is een JSX-conventie, niet een die inherent is aan JavaScript.

Maar als je raar ziet 0s in je gesmolten JSX, denk los vals beheer.


45
2018-04-29 18:14



Het is gewoon de logische operator NOT, twee keer: het wordt gebruikt om iets om te zetten naar boolean, bijvoorbeeld:

true === !!10

false === !!0

44
2018-04-24 08:18



Het converteert het achtervoegsel naar een Booleaanse waarde.


28
2017-09-10 17:27



Het is een dubbelganger not operatie. De eerste ! converteert de waarde naar Boolean en inverteert de logische waarde ervan. De seconde ! inverteert de logische waarde terug.


21
2017-09-10 17:28