Quel est le !! (non pas) opérateur en JavaScript?

3109

J'ai vu un code qui semble utiliser un opérateur , je ne reconnais pas, sous la forme de deux points d'exclamation, comme suit: !!. Quelqu'un peut-il me dire ce que fait cet opérateur?

Le contexte dans lequel j'ai vu cela était,

this.vertical = vertical !== undefined ? !!vertical : this.vertical;
Théorie de l'hexagone
la source
946
Souvenez-vous-en par "bang, bang tu es booléen"
Gus
75
Pour mémoire, ne faites pas ce qui est cité ici. À faire if(vertical !== undefined) this.vertical = Boolean(vertical);- il est beaucoup plus propre et plus clair de ce qui se passe, ne nécessite aucune affectation inutile, est entièrement standard et est tout aussi rapide (sur FF actuel et Chrome) jsperf.com/boolean-conversion-speed .
Phil H
73
!! n'est pas un opérateur. C'est juste le! opérateur deux fois.
Vivek
11
Juste pour mémoire, ce Boolean(5/0)n'est pas la même chose que!!5/0
schabluk
63
@schabluk, pour mémoire, l' ordre des opérations est la raison de !!5/0produire Infinityplutôt que true, comme produit par Boolean(5/0). !!5/0est équivalent à (!!5)/0- aka true/0- car l' !opérateur a une priorité plus élevée que l' /opérateur. Si vous vouliez booléeniser en 5/0utilisant un double coup, vous auriez besoin d'utiliser !!(5/0).
matty

Réponses:

2750

Convertit Objecten boolean. Si elle était Falsey (par exemple 0, null, undefined, etc.), il sera false, par ailleurs, true.

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

Ce !!n'est donc pas un opérateur, c'est juste l' !opérateur deux fois.

Exemple du monde réel "Tester la version IE":

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

Si vous ⇒

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

Mais si vous ⇒

console.log(!!navigator.userAgent.match(/MSIE 8.0/));  
// returns either true or false
stevehipwell
la source
123
Il convertit un non-booléen en un booléen inversé (par exemple,! 5 serait faux, car 5 est une valeur non fausse dans JS), puis booléen-inverse cela afin que vous obteniez la valeur d'origine en tant que booléen (donc !! 5 serait Sois sincère).
Chuck
111
Un moyen simple de le décrire est: Boolean (5) === !! 5; Même casting, moins de personnages.
Micah Snyder
39
Ceci est utilisé pour convertir les valeurs véridiques en valeurs booléennes true et les valeurs fausses trop booléennes false.
theetoolman
13
@Micah Snyder veille à ce qu'en JavaScript, il est préférable d'utiliser des primitives booléennes au lieu de créer des objets qui booléens avec de nouveaux booléens (). Voici un exemple pour voir la différence: jsfiddle.net/eekbu
victorvartan
4
Pour autant que je sache, ce modèle bang-bang n'est pas utile dans une instruction if (… _; uniquement dans une instruction return d'une fonction qui devrait renvoyer un booléen.
rds
854

C'est une façon horriblement obscure de faire une conversion de type.

!n'est pas . Il en !trueest de même falseet !falseest true. !0est true, et !1est false.

Vous convertissez donc une valeur en booléen, puis vous l'inversez, puis vous l'inversez à nouveau.

// 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
la source
74
!! false = false. !! true = true
cllpse
89
La variante "beaucoup plus facile à comprendre" est-elle vraiment beaucoup plus facile à comprendre ici? La vérification par rapport à 0 n'est pas une vérification réelle par rapport à 0, mais une vérification par rapport à la liste de valeurs quelque peu étrange que Javascript considère comme égale à 0. userId ? true : false indique plus clairement qu'il y a une conversion en cours et gère le cas où la valeur de userId pourrait avoir été explicitement définie surundefined
Ben Regenspan
54
Mon cerveau n'a pas de problème de décodage !!vardans Boolean(var).. et !!est plus rapide (moins d' instructions à traiter) et plus court que les solutions de rechange.
adamJLev
7
@RickyClarkson est principalement pour la lisibilité car syntaxiquement ce n'est pas nécessaire. Certains utilisent la convention de toujours encapsuler un conditionnel entre parenthèses pour le distinguer du reste de l'expression.
Dave Rager
8
Je suis en désaccord avec cela. userId != 0est vrai pour null, NaNet undefined, mais faux pour false. Si vous voulez exactement ce comportement, vous devriez probablement être explicite à ce sujet. Mais même si cela fonctionnait exactement de la même manière !!userId, il n'est pas clair si vous voulez que ces valeurs apparaissent fausses ici, ou si vous n'avez simplement pas pris en compte les règles de conversion de type Javascript.
philh
449

!!exprrenvoie une valeur booléenne ( trueou false) selon la véracité de l'expression. Il est plus logique lorsqu'il est utilisé sur des types non booléens. Considérez ces exemples, en particulier le 3e exemple et les suivants:

          !!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
la source
63
A noter:!!new Boolean(false) // true
Camilo Martin
43
... mais aussi!!Boolean(false) // false
Camilo Martin
97
new Boolean(false)est un objet et un objet est véridique même s'il contient une valeur falsifiée!
Salman A
3
Oui , je sais, mais considère le fait que la plupart des constructeurs indigènes ( String, Number, Date, etc.) sont destinés à être appelable comme des fonctions aussi, mais dans ce cas , le résultat est différent!
Camilo Martin
4
@CamiloMartin: vient de réaliser que new Boolean(false)retourne un objectcertain temps Boolean(false)renvoie la primitive false . J'espère que cela a du sens.
Salman A
155

Préparez du thé:

!!n'est pas un opérateur. C'est la double utilisation de !- qui est l'opérateur logique "non".


En théorie:

! détermine la "vérité" de ce qu'une valeur n'est pas:

  • La vérité est que ce falsen'est pas le cas true(c'est pourquoi cela se !falsetraduit par true)

  • La vérité est que ce truen'est pas le cas false(c'est pourquoi cela se !truetraduit par false)


!!détermine la « vérité » de ce qu'est une valeur non pas:

  • La vérité est que truece n'est pas non true (c'est pourquoi les !!truerésultats dans true)

  • La vérité est que falsece n'est pas non false (c'est pourquoi les !!falserésultats dans false)


Ce que nous voulons déterminer dans la comparaison, c'est la «vérité» sur la valeur d'une référence, et non la valeur de la référence elle-même. Il existe un cas d'utilisation où nous pourrions vouloir connaître la vérité sur une valeur, même si nous nous attendons à ce que la valeur soit false(ou falsey), ou si nous nous attendons à ce que la valeur ne soit pas typeof boolean.


En pratique:

Considérons une fonction concise qui détecte la fonctionnalité (et dans ce cas, la compatibilité de la plate-forme) au moyen du typage dynamique (aka "duck typing"). Nous voulons écrire une fonction qui retourne truesi le navigateur d'un utilisateur prend en charge l' <audio>élément HTML5 , mais nous ne voulons pas que la fonction génère une erreur si elle <audio>n'est pas définie; et nous ne voulons pas utiliser try ... catchpour gérer les erreurs possibles (car elles sont grossières); et nous ne voulons pas non plus utiliser une vérification à l'intérieur de la fonction qui ne révélera pas systématiquement la vérité sur la fonctionnalité (par exemple, document.createElement('audio')créera toujours un élément appelé <audio>même si HTML5 <audio>n'est pas pris en charge).


Voici les trois approches:

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

Chaque fonction accepte un argument pour a <tag>et an attributeà rechercher, mais chacune renvoie des valeurs différentes en fonction de ce que les comparaisons déterminent.

Mais attendez, il y a plus!

Certains d'entre vous ont probablement remarqué que dans cet exemple spécifique, on pourrait simplement vérifier une propriété en utilisant les moyens légèrement plus performants de vérifier si l'objet en question a une propriété. Il y a deux façons de faire ça:

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

Nous nous éloignons ...

Aussi rares que soient ces situations, il peut exister quelques scénarios où le moyen le plus concis, le plus performant et donc le plus préféré d'obtenir trued'une valeur non booléenne, peut-être indéfinie, est bien d'utiliser !!. Espérons que cela clarifie ridiculement les choses.

Benny
la source
1
réponse totalement génial, mais je ne vois pas l'utilité de la !! construction. Puisqu'une if()instruction transforme déjà l'expression en booléen, le fait de transposer explicitement la valeur de retour d'une fonction de test en booléen est redondant - puisque "véracité" === true en ce qui concerne une if()instruction de toute façon. Ou est-ce que je manque un scénario où vous avez besoin d'une expression véridique pour être réellement booléen true?
Tom Auger
1
Les if()instructions @TomAuger font un cast booléen contre les valeurs de falsey, mais disons que vous voulez réellement définir un drapeau booléen sur un objet - il ne le cast pas comme le fait une if()instruction. Par exemple object.hasTheThing = !!castTheReturnValToBoolNoMatterWhat(), définirait soit trueou falseau lieu de la valeur de retour réelle. Un autre exemple est peut-être que tous les administrateurs sont idde 0et les non-administrateurs sont id 1ou supérieur. Pour obtenir truesi quelqu'un n'est pas un administrateur, vous pouvez le faire person.isNotAdmin = !!admin.id. Peu de cas d'utilisation, mais c'est concis quand il y en a.
Benny
103

!!convertit la valeur à sa droite en sa valeur booléenne équivalente. (Pensez à la manière du pauvre homme de "taper des caractères"). Son intention est généralement de transmettre au lecteur que le code ne se soucie pas ce que la valeur est dans la variable, mais ce que c'est la valeur « vérité » est.

Croissant frais
la source
4
Ou dans le cas d'une valeur booléenne à droite, cela ne fait rien.
Daniel A. White
3
@Daniel: !retourne toujours la valeur vers la droite. Dans le cas d'un booléen, le plus à droite !nie la valeur, tandis que le plus à gauche la !nie à nouveau. L'effet net est qu'il n'y a pas de changement, mais la plupart des moteurs génèrent des codes op pour la double négation.
Crescent Fresh
Mais à quoi ça sert? Si je le fais, if(0){...Javascript sait déjà que c'est faux. Pourquoi vaut-il mieux dire if(!!0){...?
CodyBugstein
le point concerne les variables dont vous ne connaissez peut-être pas le contenu; s'il peut s'agir d'un entier ou d'une chaîne, d'un objet ou null, non défini, etc. C'est un moyen facile de tester l'existence.
mix3d
71

!!fooapplique l'opérateur unary not deux fois et est utilisé pour convertir en type booléen similaire à l'utilisation d'unaire plus +foopour convertir en nombre et concaténer une chaîne vide ''+foopour convertir en chaîne.

Au lieu de ces hacks, vous pouvez également utiliser les fonctions constructeurs correspondant aux types primitifs ( sans utiliser new) pour convertir explicitement des valeurs, c'est-à-dire

Boolean(foo) === !!foo
Number(foo)  === +foo
String(foo)  === ''+foo
Christoph
la source
Mais alors vous pouvez rencontrer des problèmes avec instanceof. new Boolean (1) instanceof Object -> true !! 1 instanceof Object -> false
Seamus
13
non, vous ne pouvez pas: notez que les fonctions constructeur sont appelées sans new- comme mentionné explicitement dans ma réponse
Christoph
2
fantastique! Ceci est utile pour un petit hack lorsque vous devez évaluer les chaînes avec "0" comme faux au lieu de vrai. (c'est-à-dire lors de la lecture de valeurs à partir de sélections, car elles sont lues en tant que chaîne). Donc, si vous voulez considérer "0" comme négatif (booléen faux), en supposant x="0"juste faire: x=!!+x; //falsequi est le même que Boolean(Number(x))Number (ou + x) convertit la chaîne "0" en 0, ce qui est évalué comme faux, puis booléen (!! x) le transforme directement en booléen. Peasy facile!
DiegoDD
2
@DiegoDD pourquoi choisiriez-vous !!+xvs x !== "0"?
placeybordeaux
@placeybordeaux parce que par exemple, vous voudrez peut-être convertir la valeur et l'affecter à une autre variable, peu importe si vous allez la comparer à autre chose ou non.
DiegoDD
67

Autant de réponses qui font la moitié du travail. Oui, !!Xpourrait être lu comme "la véracité de X [représentée comme un booléen]". Mais !!n'est pas, pratiquement parlant, si important pour déterminer si une seule variable est (ou même si plusieurs variables sont) véridiques ou fausses. !!myVar === trueest le même que juste myVar. La comparaison !!Xavec un "vrai" booléen n'est pas vraiment utile.

Ce que vous gagnez, !!c'est la possibilité de vérifier la véracité de plusieurs variables les unes par rapport aux autres de manière reproductible, standardisée (et compatible avec JSLint).

Simplement lancer :(

C'est...

  • 0 === falseest false.
  • !!0 === falseest true.

Ce qui précède n'est pas si utile. if (!0)vous donne les mêmes résultats que if (!!0 === false). Je ne peux pas penser à un bon cas pour convertir une variable en booléen, puis comparer à un "vrai" booléen.

Voir "== et! =" Dans les instructions de JSLint (note: Crockford déplace un peu son site; ce lien est susceptible de mourir à un moment donné) pour un peu sur pourquoi:

Les opérateurs == et! = Saisissent la coercition avant de comparer. Ceci est mauvais car cela rend vrai '\ t \ r \ n' == 0. Cela peut masquer des erreurs de type. JSLint ne peut pas déterminer de manière fiable si == est utilisé correctement, il est donc préférable de ne pas utiliser du tout == et! = Et de toujours utiliser les opérateurs === et! == les plus fiables à la place.

Si vous vous souciez seulement de la véracité ou de la fausseté d'une valeur, utilisez le formulaire court. Au lieu de
(foo != 0)

dis le
(foo)

et au lieu de
(foo == 0)

dire
(!foo)

Notez qu'il existe des cas non intuitifs où un booléen sera converti en un nombre ( trueest converti en 1et falseen 0) lors de la comparaison d'un booléen en un nombre. Dans ce cas, !!pourrait être mentalement utile. Bien que, encore une fois, ce sont des cas où vous comparez un non-booléen à un booléen dur, ce qui est, imo, une grave erreur. if (-1)est toujours le chemin à parcourir ici.

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

Et les choses deviennent encore plus folles selon votre moteur. WScript, par exemple, remporte le prix.

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

En raison de l' historique jive de Windows , cela produira -1 dans une boîte de message! Essayez-le dans une invite cmd.exe et voyez! Mais WScript.echo(-1 == test())vous donne toujours 0, ou WScript false. Détourne le regard. C'est hideux.

Comparaison de la véracité :)

Mais que se passe-t-il si j'ai deux valeurs dont je dois vérifier la véracité / la fausseté égales?

Imaginez que nous avons myVar1 = 0;et myVar2 = undefined;.

  • myVar1 === myVar2est 0 === undefinedet est évidemment faux.
  • !!myVar1 === !!myVar2est !!0 === !!undefinedet est vrai! Même vérité! (Dans ce cas, les deux "ont une vérité de fausseté".)

Donc, le seul endroit où vous auriez vraiment besoin d'utiliser des "variables booléennes" serait si vous aviez une situation où vous vérifiez si les deux variables ont la même véracité, non? C'est-à-dire, utilisez !!si vous avez besoin de voir si deux vars sont à la fois véridiques ou fausses (ou non), c'est-à-dire de véracité égale (ou non) .

Je ne peux pas penser à un excellent cas d'utilisation non artificiel pour cette désinvolture. Vous avez peut-être des champs "liés" dans un formulaire?

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

Alors maintenant, si vous avez une vérité pour les deux ou une fausse pour le nom et l'âge du conjoint, vous pouvez continuer. Sinon, vous n'avez qu'un seul champ avec une valeur (ou un mariage arrangé très tôt) et devez créer une erreur supplémentaire sur votre errorObjectscollection.


EDIT 24 oct 2017, 6 fév 19:

Bibliothèques tierces qui attendent des valeurs booléennes explicites

Voici un cas intéressant ... !!pourrait être utile lorsque des bibliothèques tierces attendent des valeurs booléennes explicites.

Par exemple, False dans JSX (React) a une signification spéciale qui n'est pas déclenchée par une simple fausseté. Si vous avez essayé de renvoyer quelque chose comme ce qui suit dans votre JSX, en attendant un int dans messageCount...

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

... vous pourriez être surpris de voir React effectuer un rendu 0lorsque vous n'avez aucun message. Vous devez explicitement retourner false pour que JSX ne soit pas rendu. L'instruction ci-dessus renvoie 0, que JSX rend avec bonheur, comme il se doit. Cela ne peut pas dire que vous n'en aviez pas Count: {messageCount && <div>Get your count to zero!</div>}(ou quelque chose de moins artificiel).

  • Une solution implique le bangbang, qui coercé 0en !!0, qui est false:
    {!!messageCount && <div>You have messages!</div>}

  • Les documents de JSX vous suggèrent d'être plus explicite, d'écrire du code auto-commenté et d'utiliser une comparaison pour forcer à un booléen.
    {messageCount > 0 && <div>You have messages!</div>}

  • Je suis plus à l'aise pour gérer moi-même la fausseté avec un ternaire -
    {messageCount ? <div>You have messages!</div> : false}

Même chose dans Typescript: si vous avez une fonction qui retourne un booléen (ou si vous assignez une valeur à une variable booléenne), vous [généralement] ne pouvez pas retourner / assigner une valeur booléenne-y; ce doit être un booléen fortement typé. Cela signifie que si siff myObjectest fortement typé , return !myObject;fonctionne pour une fonction renvoyant un booléen, mais return myObject;ne le fait pas. Vous devez return !!myObjectcorrespondre aux attentes de Typescript.

L'exception pour Typescript? Si myObjectc'était un any, vous êtes de retour dans le Wild West de JavaScript et pouvez le renvoyer sans !!, même si votre type de retour est un booléen.

Gardez à l'esprit que ce sont des conventions JSX et Typescript , pas celles inhérentes à JavaScript .

Mais si vous voyez des 0s étranges dans votre JSX rendu, pensez à une gestion de fausseté lâche.

ruffin
la source
Bonne explication. Alors diriez-vous le !! n'est pas strictement nécessaire dans cet exemple de détection des fonctionnalités de Worker ? if (!!window.Worker)
jk7
2
Non, vous n'en auriez pas besoin. La vérité et true«extérieurement» fonctionnent exactement de la même manière dans un if. Je continue d'essayer, mais je ne peux pas penser à une raison pour préférer jeter la vérité à une valeur booléenne en dehors du type de cas compliqué "comparer les vérités" ci-dessus, sauf pour la lisibilité si vous réutilisez la valeur plus tard, comme dans l' qexemple de la bibliothèque . Mais même alors, c'est un raccourci avec perte d'informations, et je dirais que vous feriez mieux d'évaluer la véracité à chaque fois.
ruffin
React est la principale raison pour laquelle nous avons commencé à utiliser le !! modèle, mais il se trouve que c'est une chose très pratique et reproductible. Je n'ai qu'à m'inquiéter de la véracité ou de la fausseté de quelque chose, pas du type sous-jacent.
Les votes négatifs sans commentaires rendent difficile de répondre à votre préoccupation! Faites-moi savoir ce qui semble mauvais, et je serai heureux de vous en parler.
ruffin
55

C'est juste l'opérateur NOT logique, deux fois - il est utilisé pour convertir quelque chose en booléen, par exemple:

true === !!10

false === !!0
Greg
la source
3
Pourquoi diable feriez-vous cela? Utilisez le ! pour convertir en booléen puis utiliser === pour comparer le type? Acceptez simplement que vous n'avez aucune sécurité de type et faites val> 0 ou quelque chose.
Darren Clark le
43
@Darren: Il ne compare pas les types; il vous dit quels sont les résultats, en écrivant des affirmations dans sa réponse.
Courses de légèreté en orbite
32

Il convertit le suffixe en valeur booléenne.

Paul McMillan
la source
26

C'est une double notopération. Le premier !convertit la valeur en booléen et inverse sa valeur logique. Le second !inverse la valeur logique.

Bill le lézard
la source
26

Il semble que l' !!opérateur entraîne une double négation.

var foo = "Hello World!";

!foo // Result: false
!!foo // Result: true
Steve Harrison
la source
23

Il simule le comportement de la Boolean()fonction de casting. La première NOTrenvoie une valeur booléenne quel que soit l'opérande qui lui est donné. La seconde NOTannule cette Booleanvaleur et donne ainsi la truevaleur booléenne d'une variable. Le résultat final est identique à l'utilisation de la Boolean()fonction sur une valeur.

Prakash
la source
20

! est "booléen non", qui transcrit essentiellement la valeur de "enable" à son opposé booléen. La deuxième ! inverse cette valeur. Donc, !!enablesignifie «pas activé», ce qui vous donne la valeur d' enableun booléen.

Annika Backstrom
la source
18

Je pense qu'il convient de mentionner qu'une condition combinée avec ET / OU logique ne renverra pas de valeur booléenne mais le dernier succès ou le premier échec en cas de && et le premier succès ou le dernier échec en cas de || de la chaîne de condition.

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

Afin de convertir la condition en un vrai littéral booléen, nous pouvons utiliser la double négation:

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

!!il utilise l' NOTopération deux fois ensemble, !convertit la valeur en a booleanet l'inverse, voici un exemple simple pour voir comment ça !!marche:

Au début, l'endroit que vous avez:

var zero = 0;

Ensuite !0, il sera converti en booléen et évalué en true, car 0 est falsy, donc vous obtenez la valeur inversée et converti en booléen, donc il est évalué en true.

!zero; //true

mais nous ne voulons pas la version booléenne inversée de la valeur, nous pouvons donc l'inverser à nouveau pour obtenir notre résultat! C'est pourquoi nous en utilisons un autre !.

Fondamentalement, !!assurez-vous que la valeur que nous obtenons est booléenne, pas fausse, véridique ou chaîne, etc.

C'est donc comme utiliser la Booleanfonction en javascript, mais un moyen simple et plus court de convertir une valeur en booléen:

var zero = 0;
!!zero; //false
Alireza
la source
15

La !!construction est un moyen simple de transformer n'importe quelle expression JavaScript en son équivalent booléen.

Par exemple: !!"he shot me down" === trueet !!0 === false.

Navin Rauniyar
la source
2
Très proche de la distinction importante. La clé est que 0 === falsec'est faux et !!0 === falsec'est vrai.
ruffin
14

Ce n'est pas un seul opérateur, c'est deux. C'est équivalent à ce qui suit et est un moyen rapide de convertir une valeur en booléen.

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

Je soupçonne que c'est un reste de C ++ où les gens remplacent le! mais pas l'opérateur booléen.

Donc, pour obtenir une réponse négative (ou positive) dans ce cas, vous devez d'abord utiliser le! pour obtenir un booléen, mais si vous voulez vérifier le cas positif, utilisez !!.

Darren Clark
la source
10

Les ifet whiledéclarations et l' ?utilisation des valeurs de vérité opérateur pour déterminer quelle branche de code à exécuter. Par exemple, les nombres zéro et NaN et la chaîne vide sont faux, mais les autres nombres et chaînes sont vrais. Les objets sont vrais, mais la valeur indéfinie et nullsont tous les deux faux.

L'opérateur de double négation !!calcule la valeur de vérité d'une valeur. Il s'agit en fait de deux opérateurs, où !!xsignifie !(!x), et se comporte comme suit:

  • Si xest une valeur fausse, !xest trueet !!xest false.
  • Si xest une vraie valeur, !xest falseet !!xest true.

Lorsqu'il est utilisé au niveau supérieur d'un contexte booléen ( if, whileou ?), l' !!opérateur est une behaviorally no-op. Par exemple, if (x)et if (!!x)signifient la même chose.

Utilisations pratiques

Cependant, il a plusieurs utilisations pratiques.

Une utilisation consiste à compresser avec perte un objet à sa valeur de vérité, afin que votre code ne contienne pas de référence à un gros objet et ne le maintienne pas en vie. Affecter !!some_big_objectà une variable au lieu de some_big_objectlaisser tomber pour le garbage collector. Cela est utile pour les cas qui produisent un objet ou une valeur fausse telle que nullou la valeur indéfinie, telle que la détection des fonctionnalités du navigateur.

Une autre utilisation, que j'ai mentionnée dans une réponse à propos de l' !!opérateur correspondant de C , est avec les outils "lint" qui recherchent les fautes de frappe courantes et les diagnostics d'impression. Par exemple, en C et en JavaScript, quelques fautes de frappe courantes pour les opérations booléennes produisent d'autres comportements dont la sortie n'est pas aussi booléenne:

  • if (a = b)est l'affectation suivie de l'utilisation de la valeur de vérité de b; if (a == b)est une comparaison d'égalité.
  • if (a & b)est un ET au niveau du bit; if (a && b)est un ET logique. 2 & 5est 0(une fausse valeur); 2 && 5est vrai.

L' !!opérateur rassure l'outil lint que ce que vous avez écrit est ce que vous vouliez dire: faites cette opération, puis prenez la valeur de vérité du résultat.

Une troisième utilisation consiste à produire un XOR logique et un XNOR logique. En C et en JavaScript, a && beffectue un ET logique (vrai si les deux côtés sont vrais) et a & beffectue un ET au niveau du bit. a || beffectue un OU logique (vrai si au moins un est vrai) et a | beffectue un OU au niveau du bit. Il existe un XOR au niveau du bit (OU exclusif) a ^ b, mais il n'y a pas d'opérateur intégré pour le XOR logique (vrai si exactement un côté est vrai). Vous pouvez, par exemple, vouloir autoriser l'utilisateur à saisir du texte dans exactement l'un des deux champs. Ce que vous pouvez faire est de convertir chacun à une valeur de vérité et de les comparer: !!x !== !!y.

Damian Yerrick
la source
8

Double négation booléenne. Souvent utilisé pour vérifier si la valeur n'est pas indéfinie.

Sergey Ilinsky
la source
8

Des tonnes de bonnes réponses ici, mais si vous avez lu jusqu'ici, cela m'a aidé à «l'obtenir». Ouvrez la console sur Chrome (etc.) et commencez à taper:

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

Naturellement, ce sont les mêmes que de simplement taper !! someThing, mais les parenthèses ajoutées pourraient aider à le rendre plus compréhensible.

Warren Davis
la source
8

!!x est un raccourci pour Boolean(x)

Le premier coup oblige le moteur js à fonctionner Boolean(x)mais a également pour effet secondaire d'inverser la valeur. Ainsi, le deuxième coup annule l'effet secondaire.

Greg Gum
la source
8

Cela oblige tout à booléen.

Par exemple:

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
la source
7

Cette question a reçu une réponse assez complète, mais j'aimerais ajouter une réponse qui, je l'espère, est aussi simplifiée que possible, en donnant le sens de !! aussi simple à saisir que possible.

Parce que javascript a ce qu'on appelle des valeurs "véridiques" et "falsey", il existe des expressions qui, lorsqu'elles sont évaluées dans d'autres expressions, entraîneront une condition vraie ou fausse, même si la valeur ou l'expression examinée n'est pas réellement trueou false.

Par exemple:

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

Si cet élément existe réellement, l'expression sera évaluée comme vraie et le bloc de code sera exécuté.

Toutefois:

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

... n'entraînera PAS une condition vraie et le bloc de code ne sera pas exécuté, même si l'élément existe.

Pourquoi? Parce que document.getElementById()c'est une expression "véridique" qui sera évaluée comme vraie dans cette if()déclaration, mais ce n'est pas une valeur booléenne réelle de true.

Le double "non" dans ce cas est assez simple. C'est simplement deux nots dos à dos.

Le premier "inverse" simplement la valeur de vérité ou de falsey, résultant en un type booléen réel, puis le second le "retourne" à nouveau à son état d'origine, mais maintenant dans une valeur booléenne réelle. De cette façon, vous avez de la cohérence:

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

et

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

retournera à la fois vrai, comme prévu.

Kirby L. Wallace
la source
7

Je voulais juste ajouter ça

if(variableThing){
  // do something
}

est le même que

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

Mais cela peut être un problème lorsque quelque chose n'est pas défini.

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

L'astuce ici est que la chaîne de &&s retournera la première valeur de falsey qu'elle trouve - et cela peut être alimenté à une instruction if etc. Donc si b.foo n'est pas défini, il retournera non défini et sautera l' b.foo.barinstruction, et nous n'obtiendrons pas Erreur.

Les valeurs ci-dessus renvoient undefined mais si vous avez une chaîne vide, false, null, 0, undefined, ces valeurs seront renvoyées et dès que nous les rencontrerons dans la chaîne - []et {}sont toutes les deux "véridiques" et nous continuerons dans le soi-disant " && chaîne "à la valeur suivante à droite.

PS Une autre façon de faire la même chose est que (b || {}).foo, si b n'est pas défini, alors ce b || {}sera le cas {}, et vous accéderez à une valeur dans un objet vide (pas d'erreur) au lieu d'essayer d'accéder à une valeur dans "non défini" (provoque une erreur ). Donc, (b || {}).fooc'est la même chose b && b.fooet ((b || {}).foo || {}).barc'est la même chose que b && b.foo && b.foo.bar.

Ryan Taylor
la source
bon point - changé ma réponse. Cela ne se produit que sur un objet lorsqu'il est imbriqué à trois niveaux de profondeur, car comme vous l'avez dit ({}).anythingdonneraundefined
Ryan Taylor
5

Après avoir vu toutes ces bonnes réponses, je voudrais ajouter une autre raison d'utiliser !!. Actuellement, je travaille en Angular 2-4 (TypeScript) et je veux retourner un booléen comme falselorsque mon utilisateur n'est pas authentifié. S'il n'est pas authentifié, la chaîne de jetons serait nullou "". Je peux le faire en utilisant le bloc de code suivant:

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

voici un morceau de code de js angulaire

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

 var rafSupported = !!requestAnimationFrame;

leur intention est de définir rafSupported sur true ou false en fonction de la disponibilité de la fonction dans requestAnimationFrame

il peut être réalisé en vérifiant de la manière suivante en général:

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

le chemin court pourrait être d'utiliser !!

rafSupported = !!requestAnimationFrame ;

donc si requestAnimationFrame a été affecté à une fonction, alors! requestAnimationFrame serait faux et un de plus! ce serait vrai

si requestAnimationFrame était indéfini, alors! requestAnimationFrame serait vrai et un de plus! ce serait faux

JeevanReddy Avanaganti
la source
3

Certains opérateurs en JavaScript effectuent des conversions de type implicites et sont parfois utilisés pour la conversion de type.

L' !opérateur unaire convertit son opérande en booléen et le nie.

Ce fait conduit à l'idiome suivant que vous pouvez voir dans votre code source:

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

Utilisez deux fois l'opérateur logique,
cela signifie! True = false
et !! true = true

Abhay Dixit
la source
3

Renvoie la valeur booléenne d'une variable.

Au lieu de cela, la Booleanclasse peut être utilisée.

(veuillez lire les descriptions des codes)

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`

À savoir, Boolean(X) = !!Xen cours d'utilisation.

Veuillez vérifier l'extrait de code ci-dessous

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
la source