Domanda Qual 'é !! (non non) operatore in JavaScript?


Ho visto un codice che sembra utilizzare un operatore che non riconosco, sotto forma di due punti esclamativi, in questo modo: !!. Qualcuno può dirmi cosa fa questo operatore?

Il contesto in cui ho visto questo era,

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

2314
2018-04-24 08:13


origine


risposte:


costringe oObject al booleano. Se fosse falso (ad esempio 0, null, undefined, ecc.), lo sarà false, altrimenti, true.

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

Così !! non è un operatore, è solo il ! operatore due volte.

Esempio di mondo reale "Prova versione IE":

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

Se tu ⇒

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

ma se tu ⇒

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

2067
2018-04-24 08:18



È un modo orribilmente oscuro per fare una conversione di tipo.

! è NON. Così !true è false, e !false è true. !0 è true, e !1 è false.

Quindi stai convertendo un valore in un valore booleano, quindi invertendolo, quindi invertendolo nuovamente.

// 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 restituisce un valore booleano (true o false) dipende da truthiness dell'espressione. Ha più senso se usato su tipi non booleani. Considera questi esempi, specialmente il terzo esempio e in poi:

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



Prepara un po 'di tè:

!! non è un operatore. È il doppio uso di ! - che è l'operatore logico "non".


In teoria:

! determina la "verità" di ciò che un valore non è:

  • La verità è che false non è true (Ecco perchè !false risultati in true)

  • La verità è che true non è false (Ecco perchè !true risultati in false)


!! determina la "verità" di ciò che è un valore non non:

  • La verità è che true non è non  true (Ecco perchè !!true risultati in true)

  • La verità è che false non è non  false (Ecco perchè !!false risultati in false)


Ciò che desideriamo determinare nel confronto è la "verità" di il valore di un riferimento, non il valore di il riferimento stesso. C'è un caso d'uso in cui potremmo voler sapere la verità su un valore, anche se ci aspettiamo che il valore sia false (o falso), o se ci aspettiamo che il valore non sia typeof boolean.


In pratica:

Si consideri una funzione concisa che rileva funzionalità funzionalità (e in questo caso, la compatibilità della piattaforma) per mezzo di digitazione dinamica (aka "duck typing"). Vogliamo scrivere una funzione che ritorna true se il browser di un utente supporta HTML5 <audio> elemento, ma non vogliamo che la funzione lanci un errore se <audio> è indefinito; e non vogliamo usare try ... catch gestire eventuali errori (perché sono grossolani); e anche non vogliamo utilizzare un controllo all'interno della funzione che non rivelerà in modo coerente la verità sulla funzione (ad esempio, document.createElement('audio') creerà comunque un elemento chiamato <audio> anche se HTML5 <audio> non è supportato).


Ecco i tre approcci:

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

Ogni funzione accetta un argomento per a <tag> e un attribute da cercare, ma ognuno restituisce valori diversi in base a ciò che determina il confronto.

Ma aspetta, c'è di più!

Alcuni di voi probabilmente hanno notato che in questo esempio specifico, si potrebbe semplicemente verificare una proprietà usando il leggermente più performante mezzi per verificare se l'oggetto in questione ha una proprietà. Ci sono due modi per farlo:

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

Stiamo divagando ...

Per quanto rare possano essere queste situazioni, potrebbero esserci alcuni scenari in cui il modo più conciso, più performante e quindi il modo più preferito di ottenere true da un valore non booleano, possibilmente indefinito, si usa effettivamente !!. Spero che questo lo ridicolizzi in modo ridicolo.


127
2018-02-22 23:45



!! converte il valore a destra di esso al suo valore booleano equivalente. (Pensa al modo in cui il "tipo-casting" del povero). Suo intento è solito comunicare al lettore che il codice non interessa che cosa il valore è nella variabile, ma di cosa si tratta valore "verità" è.


87
2017-09-10 17:26



!!foo applica l'operatore unary not due volte e viene utilizzato per eseguire il cast su un tipo booleano simile all'uso di unario plus +foo per eseguire il cast al numero e concatenare una stringa vuota ''+foo per eseguire il cast alla stringa.

Invece di questi hack, puoi anche usare le funzioni di costruzione corrispondenti ai tipi primitivi (senza utilizzando new) per esprimere espressamente valori, es

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

59
2017-09-10 21:15



Così tante risposte fanno metà del lavoro. Sì, !!X potrebbe essere letto come "la verità di X [rappresentato come un booleano]". Ma !! non è, in pratica, così importante per capire se una singola variabile è (o anche se molte variabili sono) verità o falsità. !!myVar === true è lo stesso di solo myVar. confrontando !!X per un "vero" booleano non è veramente utile.

Con cosa guadagni !! è la capacità di verificare la veridicità di più variabili uno contro l'altro in modo ripetibile, standardizzato (e amichevole con JSLint).

Semplicemente casting :(

Questo è...

  • 0 === false è false.
  • !!0 === false è true.

Quanto sopra non è così utile. if (!0) ti dà gli stessi risultati di if (!!0 === false). Non riesco a pensare a un buon caso per il cast di una variabile in booleana e quindi in un confronto con un "vero" booleano.

Vedi "== and! =" Da Le indicazioni di JSLint (nota: Crockford sta spostando il suo sito un po ', quel collegamento è suscettibile di morire ad un certo punto) per un po' sul perché:

Gli operatori == e! = Digitano la coercizione prima di confrontare. Questo è male perché causa '\ t \ r \ n' == 0 per essere vero. Questo può mascherare errori di tipo. JSLint non può determinare in modo affidabile se == viene usato correttamente, quindi è meglio non usare == e! = A tutti e usare sempre gli operatori === e! == più affidabili.

Se ti interessa solo che un valore sia vero o falso, usa il modulo breve. Invece di
(foo != 0)

basta dire
(foo)

e invece di
(foo == 0)

dire
(!foo)

Nota che ce ne sono alcuni casi non intuitivi dove un booleano sarà lanciato su un numero (true è castato a 1 e false a 0) quando si confronta un valore booleano con un numero. In questo caso, !! potrebbe essere mentalmente utile Anche se, di nuovo, questi sono casi in cui stai confrontando un booleano non booleano con un hard-typed, che è, imo, un grave errore.  if (-1) è ancora la strada da percorrere qui.

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

E le cose diventano ancora più folli a seconda del tuo motore. WScript, ad esempio, vince il premio.

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

Per colpa di alcune jive storiche di Windows, che emetterà -1 in una finestra di messaggio! Provalo in un prompt di cmd.exe e guarda! Ma WScript.echo(-1 == test()) ti dà ancora 0 o WScript false. Guarda lontano. È orribile.

Confrontando la verità :)

Ma cosa succede se ho due valori che devo controllare per truthi / falsi-nità uguali?

Fingere di avere myVar1 = 0; e myVar2 = undefined;.

  • myVar1 === myVar2 è 0 === undefined ed è ovviamente falso.
  • !!myVar1 === !!myVar2 è !!0 === !!undefined ed è vero! Stessa sincerità! (In questo caso, entrambi "hanno una verità di falsità".)

Quindi l'unico posto in cui avresti davvero bisogno di usare "variabili boolean-cast" sarebbe se tu avessi una situazione in cui stai controllando se entrambe le variabili hanno stesso verità, giusto? Questo è, uso !! se hai bisogno di vedere se ci sono due vars sia sincero che falso (o non), cioè, di uguale (o no) truthiness.

Non riesco a pensare a un caso d'uso grandioso e non inventato per quella mano. Forse hai campi "collegati" in una forma?

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

Quindi ora se hai una verità per entrambi o una falsità sia per il nome del coniuge che per l'età, puoi continuare. Altrimenti hai solo un campo con un valore (o un matrimonio organizzato molto presto) e devi creare un errore in più sul tuo errorObjects collezione.


EDIT 24 ott 2017: 

Librerie di terze parti che prevedono valori booleani espliciti

Ecco un caso interessante ... !! potrebbe essere utile quando le librerie di terze parti prevedono valori booleani espliciti.

Per esempio, False in JSX (React) ha un significato speciale questo non è innescato dalla semplice falsità. Se hai provato a restituire qualcosa di simile al tuo JSX, aspettandoti una int in messageCount...

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

... potresti essere sorpreso di vedere React render a 0 quando hai zero messaggi. Devi restituire esplicitamente false affinché JSX non esegua il rendering. La dichiarazione di cui sopra ritorna 0, che JSX rende felicemente, come dovrebbe. Non può dirti che non l'hai avuto Count: {messageCount && <div>Get your count to zero!</div>} (o qualcosa di meno inventato).

  • Una correzione riguarda il bangbang, che costringe 0 in !!0, che è false:
    {!!messageCount && <div>You have messages!</div>}

  • I documenti di JSX suggeriscono che tu sia più esplicito, scrivi il codice auto-commentante e usa un confronto per forzare un booleano.
    {messageCount > 0 && <div>You have messages!</div>}

  • Sono più a mio agio nel gestire la falsità con un ternario -
    {messageCount ? <div>You have messages!</div> : false}

Tieni presente che Questo è una convenzione JSX, non uno inerente a JavaScript.

Ma se vedi strano 0s nella tua JSX renderizzata, pensa alla gestione falsy allentata.


45
2018-04-29 18:14



È semplicemente l'operatore logico NOT, due volte: è usato per convertire qualcosa in booleano, ad esempio:

true === !!10

false === !!0

44
2018-04-24 08:18



Converte il suffisso in un valore booleano.


28
2017-09-10 17:27



È un doppio not operazione. Il primo ! converte il valore in booleano e inverte il suo valore logico. Il secondo ! inverte il valore logico.


21
2017-09-10 17:28



Simula il comportamento del Boolean() funzione di fusione. Il primo NOT restituisce un valore booleano indipendentemente dall'operando fornito. Il secondo NOT lo nega Boolean valore e così dà il trueValore booleano di una variabile. Il risultato finale è lo stesso di usare il Boolean() funzione su un valore.


21
2018-03-23 11:53