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


J'ai vu du code qui semble utiliser un opérateur que je ne reconnais pas, sous la forme de deux points d'exclamation, comme ceci: !!. 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;

2316
2018-04-24 08:13


origine


Réponses:


Coerces oObject à booléen. Si c'était falsey (par exemple 0, null, undefined, etc.), il sera false, autrement, true.

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

Alors !! n'est pas un opérateur, c'est juste le ! opérateur deux fois.

Exemple du monde réel "Test IE version":

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

mais si vous ⇒

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

2068
2018-04-24 08:18



C'est une manière horriblement obscure de faire une conversion de type.

! est NE PAS. Alors !true est false, et !false est true. !0 est true, et !1 est false.

Vous convertissez donc une valeur en valeur booléenne, 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);

729
2017-09-10 17:28



!!expr renvoie une valeur booléenne (true ou false) en fonction de la vérité de l'expression. Cela a plus de sens lorsqu'il est utilisé sur des types non booléens. Considérez ces exemples, en particulier le 3ème exemple et 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!

372
2018-05-15 09:06



Préparez du thé:

!! n'est pas un opérateur. C'est le double usage de ! - qui est l'opérateur logique "not".


En théorie:

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

  • La vérité c'est que false n'est pas true (c'est pourquoi !false résultats dans true)

  • La vérité c'est que true n'est pas false (c'est pourquoi !true résultats dans false)


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

  • La vérité c'est que true n'est pas ne pas  true (c'est pourquoi !!true résulte en true)

  • La vérité c'est que false n'est pas ne pas  false (c'est pourquoi !!false résulte en false)


Ce que nous souhaitons déterminer dans la comparaison est la "vérité" sur la valeur d'une référence, pas la valeur de la référence elle-même. Il y a 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 de typeof boolean.


En pratique:

Envisager une fonction concise qui détecte les fonctionnalités (et dans ce cas, la compatibilité de la plate-forme) au moyen de typage dynamique (aka "dactylographie"). Nous voulons écrire une fonction qui revient true si le navigateur d'un utilisateur prend en charge HTML5 <audio> élément, mais nous ne voulons pas que la fonction jette une erreur si <audio> est indéfini; et nous ne voulons pas utiliser try ... catch gérer toutes les erreurs possibles (parce qu'elles sont grossières); et aussi nous ne voulons pas utiliser une vérification à l'intérieur de la fonction qui ne révélera pas toujours la vérité sur la fonctionnalité (par exemple, document.createElement('audio') va toujours créer un élément appelé <audio> même si HTML5 <audio> n'est pas supporté).


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 un <tag> Et un attribute à rechercher, mais ils retournent chacun 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 précis, on pouvait simplement vérifier une propriété en utilisant légèrement plus performant moyen 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 digressons ...

Aussi rares que puissent être 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 true d'une valeur non-booléenne, éventuellement indéfinie est en effet en utilisant !!. Espérons que cela efface ridiculement.


128
2018-02-22 23:45



!! convertit la valeur à droite de sa valeur booléenne équivalente. (Pensez à la manière de "type-casting" du pauvre homme). Ses intention est généralement de transmettre au lecteur que le code ne se soucie pas quelle la valeur est dans la variable, mais ce qu'il est valeur "vérité" est.


87
2017-09-10 17:26



!!foo applique deux fois l'opérateur unaire non et est utilisé pour convertir en type booléen similaire à l'utilisation de unaire plus +foo lancer un numéro et concaténer une chaîne vide ''+foo jeter à la ficelle.

Au lieu de ces hacks, vous pouvez également utiliser les fonctions constructeur correspondant aux types primitifs (sans pour autant en utilisant new) pour exprimer explicitement des valeurs,

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

59
2017-09-10 21:15



Tellement de réponses faisant la moitié du travail. Oui, !!X pourrait être lu comme "la véracité de X [représenté comme un booléen]". Mais !! n'est pas, pratiquement parlant, si important pour déterminer si une seule variable est (ou même si beaucoup de variables sont) véridique ou fausse. !!myVar === true est le même que juste myVar. Comparant !!X à un "vrai" booléen n'est pas vraiment utile.

Ce que vous gagnez avec !! est la capacité de vérifier la véracité de plusieurs variables l'un contre l'autre dans un mode reproductible, standardisé (et JSLint friendly).

Simplement coulée :(

C'est...

  • 0 === false est false.
  • !!0 === false est 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 transtyper une variable en booléen et ensuite comparer à un "vrai" booléen.

Voir "== et! =" De Les directions de JSLint (note: Crockford déplace un peu son site, ce lien risque de mourir à un moment donné) pour un peu de pourquoi:

Les opérateurs == et! = Tapent la coercition avant de la comparer. C'est mauvais car cela provoque '\ t \ r \ n' == 0 à être vrai. Cela peut masquer les 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 == et! = Du tout et d'utiliser toujours les opérateurs plus fiables === et! == à la place.

Si vous vous souciez seulement qu'une valeur est véridique ou fausse, utilisez le formulaire court. Au lieu de
(foo != 0)

dis le
(foo)

et au lieu de
(foo == 0)

dire
(!foo)

Notez qu'il y a quelques cas non intuitifs où un booléen sera jeté à un nombre (true est jeté à 1 et false à 0) en comparant un booléen à un nombre. Dans ce cas, !! pourrait être utile mentalement. Bien que, encore une fois, ce sont des cas où vous comparez un booléen non booléen à un booléen dur, ce qui est, imo, une erreur grave.  if (-1) est toujours le moyen d'aller 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 en fonction de votre moteur. WScript, par exemple, remporte le prix.

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

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

En comparant la vérité :)

Mais que se passe-t-il si j'ai deux valeurs à vérifier pour une vérité / falsité égale?

Prétendre que nous avons myVar1 = 0; et myVar2 = undefined;.

  • myVar1 === myVar2 est 0 === undefined et est évidemment faux.
  • !!myVar1 === !!myVar2 est !!0 === !!undefined et c'est vrai! Même véridicité! (Dans ce cas, les deux "ont une véracité de la 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 le même la vérité, non? C'est, utilisation !! si vous avez besoin de voir si deux vars sont à la fois la vérité ou les deux faussetés (ou non), c'est-à-dire d'égale (ou pas) vérité.

Je ne peux pas penser à un grand cas d'utilisation non-conçu pour cela. Peut-être avez-vous 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é à la fois ou une fausseté pour le nom du conjoint et l'âge, vous pouvez continuer. Sinon, vous n'avez qu'un seul champ avec une valeur (ou un mariage arrangé très tôt) et vous devez créer une erreur supplémentaire sur votre errorObjects collection.


EDIT 24 oct 2017: 

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

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

Par exemple, Faux dans JSX (React) a une signification spéciale ce n'est pas déclenché sur la simple fausseté. Si vous avez essayé de renvoyer quelque chose comme ce qui suit dans votre JSX, attendez-vous à un int messageCount...

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

... vous pourriez être surpris de voir React rendre un 0 quand vous avez zéro message. Vous devez explicitement retourner false pour que JSX ne soit pas rendu. L'instruction ci-dessus renvoie 0, que JSX rend heureusement, comme il se doit. Ça ne peut pas dire que tu n'avais pas Count: {messageCount && <div>Get your count to zero!</div>} (ou quelque chose de moins artificiel).

  • Un correctif implique le bangbang, qui contraint 0 dans !!0, lequel est false:
    {!!messageCount && <div>You have messages!</div>}

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

  • Je suis plus à l'aise avec la manipulation de fausseté avec un ternaire -
    {messageCount ? <div>You have messages!</div> : false}

Garde en tête que ce est une convention JSX, pas un inhérent à JavaScript.

Mais si vous voyez étrange 0s dans votre rendu JSX, pensez à la gestion de la falsification.


45
2018-04-29 18:14



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

44
2018-04-24 08:18



Il convertit le suffixe en une valeur booléenne.


28
2017-09-10 17:27



C'est un double not opération. La première ! convertit la valeur en boolean et inverse sa valeur logique. La deuxième ! inverse la valeur logique.


21
2017-09-10 17:28



Il simule le comportement du Boolean() fonction de moulage. La première NOT renvoie une valeur booléenne quel que soit l'opérande donné. La deuxième NOT nie que Boolean valeur et donne donc la trueValeur booléenne d'une variable Le résultat final est le même que l'utilisation du Boolean() fonctionner sur une valeur.


21
2018-03-23 11:53