Quale è !! (non no) operatore in JavaScript?


3108

Ho visto un po 'di 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 l'ho visto era

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

946
Ricordalo con "bang, bang bang boolean"
Gus

75
Solo per la cronaca, non fare ciò che è citato lì. Fai if(vertical !== undefined) this.vertical = Boolean(vertical);: è molto più chiaro e chiaro ciò che sta succedendo, non richiede assegnazioni non necessarie, è del tutto standard ed è altrettanto veloce (su FF e Chrome attuali ) jsperf.com/boolean-conversion-speed .
Phil H,

73
!! non è un operatore. È solo il! operatore due volte.
Vivek,

11
Solo per la cronaca, Boolean(5/0)non è lo stesso di!!5/0
schabluk del

63
@schabluk, per la cronaca, l' ordine delle operazioni è la ragione che !!5/0produce Infinitypiuttosto che true, come prodotto da Boolean(5/0). !!5/0equivale a (!!5)/0- aka true/0- perché l' !operatore ha una precedenza più alta /dell'operatore. Se vuoi booleanizzare 5/0usando un doppio botto, dovresti usarlo !!(5/0).
matty

Risposte:


2749

Converte Objectin boolean. Se fosse Falsey (ad esempio 0, null, undefined, etc.), sarà false, in caso contrario, true.

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

Quindi !!non è un operatore, è solo l' !operatore due volte.

Esempio di Real World "Test versione IE":

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

Se ⇒

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

Ma se ⇒

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

123
Converte un nonbooleano in un booleano invertito (ad esempio,! 5 sarebbe falso, poiché 5 è un valore non falso in JS), quindi il valore booleano lo inverte in modo da ottenere il valore originale come booleano (quindi !! 5 essere vero).
Chuck,

111
Un modo semplice per descriverlo è: Boolean (5) === !! 5; Stesso casting, meno personaggi.
Micah Snyder,

39
Questo è usato per convertire i valori di verità in veri booleani e falsi valori troppo booleani falsi.
thetoolman il

13
@Micah Snyder stai attento che in JavaScript è meglio usare primitivi booleani invece di creare oggetti che box booleani con il nuovo Booleano (). Ecco un esempio per vedere la differenza: jsfiddle.net/eekbu
victorvartan,

4
Per quanto ne so, questo modello di bang-bang non è utile all'interno di un'istruzione if (... _; solo in un'istruzione return di una funzione che dovrebbe restituire un valore booleano.
rds,

854

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

!NON lo è . Così !trueè falseed !falseè true. !0è trueed !1è false.

Quindi stai convertendo un valore in un valore booleano, quindi invertendolo, quindi invertendolo di nuovo.

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

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

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

74
!! false = false. !! true = true
cllpse

89
La variante "molto più facile da capire" è davvero molto più facile da capire qui? Il controllo rispetto a 0 non è un controllo effettivo rispetto a 0, ma un controllo rispetto all'elenco un po 'strano di valori che Javascript considera uguale a 0. userId ? true : false rende più chiaro il fatto che ci sia una conversione in corso e gestisce il caso in cui il valore di userId potrebbe essere stato esplicitamente impostato suundefined
Ben Regenspan,

54
Il mio cervello non ha alcun problema a decodificare !!varin Boolean(var)... ed !!è più veloce (meno istruzioni da elaborare) e più corto delle alternative.
adamJLev,

7
@RickyClarkson è principalmente per la leggibilità poiché sintatticamente non è richiesto. Alcuni usano la convenzione di racchiudere sempre un condizionale tra parentesi per distinguerlo dal resto dell'espressione.
Dave Rager,

8
Non sono d'accordo con questo. userId != 0è vero per null, NaNe undefined, ma falso per false. Se vuoi esattamente quel comportamento, probabilmente dovresti essere esplicito al riguardo. Ma anche se ha funzionato esattamente allo stesso modo !!userId, non è chiaro se si desidera che questi valori risultino falsi qui o se non si è riusciti a considerare le regole di conversione del tipo di Javascript.
phil

449

!!exprrestituisce un valore booleano ( trueo false) a seconda della veridicità dell'espressione. Ha più senso se utilizzato su tipi non booleani. Considera questi esempi, in particolare il terzo esempio e successivi:

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

63
Vale la pena notare:!!new Boolean(false) // true
Camilo Martin il

43
... Ma anche!!Boolean(false) // false
Camilo Martin il

97
new Boolean(false)è un oggetto e un oggetto è vero anche se contiene un valore falso!
Salman A

3
Sì, lo so, ma considero il fatto che la maggior parte dei costruttori nativi ( String, Number, Date, ecc) sono destinate ad essere richiamabile come funzioni troppo, ma in questo caso il risultato è diverso!
Camilo Martin,

4
@CamiloMartin: appena realizzato che new Boolean(false)restituisce un objectpo ' Boolean(false)restituisce la primitiva false . Spero che abbia senso.
Salman,

155

Prepara del tè:

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


In teoria:

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

  • La verità è che falsenon lo è true(ecco perché si !falsetraduce in true)

  • La verità è che truenon lo è false(ecco perché si !truetraduce in false)


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

  • La verità è che truenon lo è true (ecco perché i !!truerisultati true)

  • La verità è che falsenon lo è false (ecco perché i !!falserisultati false)


Ciò che desideriamo determinare nel confronto è la "verità" sul valore di un riferimento, non sul valore del riferimento stesso. Esiste un caso d'uso in cui potremmo voler conoscere la verità su un valore, anche se prevediamo che il valore sia false(o falso) o se prevediamo che il valore non sia di tipo boolean.


In pratica:

Prendi in considerazione una funzione concisa che rilevi la funzionalità (e in questo caso la compatibilità della piattaforma) mediante la digitazione dinamica (nota anche come "digitazione anatra"). Vogliamo scrivere una funzione che ritorni truese il browser di un utente supporta l' <audio>elemento HTML5 , ma non vogliamo che la funzione generi un errore se <audio>non è definita; e non vogliamo usare try ... catchper gestire eventuali errori (perché sono grossolani); e inoltre non vogliamo usare un segno di spunta 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 an attributeda cercare, ma ognuna restituisce valori diversi in base a ciò che determinano i confronti.

Ma aspetta, c'è di più!

Alcuni di voi probabilmente hanno notato che in questo esempio specifico, si potrebbe semplicemente verificare la presenza di una proprietà utilizzando i mezzi leggermente più performanti per verificare se l'oggetto in questione ha una proprietà. Esistono 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, possono esistere alcuni scenari in cui il mezzo più conciso, più performante e quindi il più preferito per ottenere trueda un valore non booleano, forse indefinito, è in effetti usando !!. Spero che questo ridicolmente lo chiarisca.


1
risposta assolutamente fantastica, ma non riesco a vedere l'utilità del !! costruire. Dato che if()un'istruzione lancia già l'espressione booleana, il cast esplicito del valore restituito di una funzione di test su booleano è ridondante, poiché "la veridicità" === vera per quanto riguarda if()un'istruzione. O mi sto perdendo uno scenario in cui BISOGNO di un'espressione sincera per essere effettivamente booleano true?
Tom Auger,

1
Le if()istruzioni @TomAuger lanciano valori booleani contro i valori di falsità, ma dicono che vuoi effettivamente impostare un flag booleano su un oggetto - non lo lancerà come if()fa un'istruzione. Ad esempio object.hasTheThing = !!castTheReturnValToBoolNoMatterWhat(), impostarebbe trueo falseinvece del valore di ritorno reale. Un altro esempio è forse tutti gli amministratori sono iddei 0e non amministratori sono id 1o superiore. Per ottenere truese qualcuno non è un amministratore, potresti farlo person.isNotAdmin = !!admin.id. Pochi casi d'uso, ma è conciso quando c'è.
Benny,

103

!!converte il valore a destra di esso nel suo valore booleano equivalente. (Pensa al modo in cui il povero "castista"). Il suo intento è di solito comunicare al lettore che al codice non importa quale sia il valore nella variabile, ma quale sia il suo valore "verità" .


4
O nel caso di un valore booleano a destra, non fa nulla.
Daniel A. White,

3
@Daniel: !gira ancora il valore a destra. Nel caso di un valore booleano, il più a destra !nega il valore, mentre il più a sinistra !lo nega ancora una volta. L'effetto netto è che non vi è alcun cambiamento, ma la maggior parte dei motori genererà codici op per la doppia negazione.
Crescent Fresh,

Ma qual è il punto? Se lo faccio if(0){...Javascript sa già che questo è falso. Perché è meglio dirlo if(!!0){...?
CodyBugstein,

il punto è per le variabili che potresti non conoscere il suo contenuto; se potrebbe essere un numero intero o una stringa, un oggetto o null, non definito, ecc. Questo è un modo semplice per testare l'esistenza.
mix3d

71

!!fooapplica l'operatore non unario due volte e viene utilizzato per eseguire il cast su un tipo booleano simile all'uso di unary plus +fooper eseguire il cast su numero e concatenare una stringa vuota per ''+fooeseguire il cast su stringa.

Invece di questi hack, puoi anche usare le funzioni di costruzione corrispondenti ai tipi primitivi ( senza usare new) per lanciare esplicitamente valori, ad es.

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

Ma poi puoi riscontrare problemi con instanceof. new Boolean (1) instanceof Object -> true !! 1 instanceof Object -> false
Seamus

13
no, non puoi: nota che le funzioni del costruttore sono chiamate senza new- come esplicitamente menzionato nella mia risposta
Christoph

2
fantastico! Ciò è utile per un piccolo hack quando è necessario valutare le stringhe con "0" come false anziché true. (vale a dire quando si leggono valori da selezioni, perché sono letti come String). Quindi, se vuoi considerare "0" come negativo (booleano falso), asumendo x="0"basta fare: x=!!+x; //falseche è lo stesso di Boolean(Number(x))Numero (o + x) converte la stringa "0" in 0, che valuta come falso, e quindi booleano (!! x) lo lancia direttamente in booleano. Vai tranquillo!
DiegoDD,

2
@DiegoDD perché dovresti scegliere !!+xvs x !== "0"?
Placeybordeaux,

@placeybordeaux perché ad esempio potresti voler convertire il valore e assegnarlo ad altre variabili, indipendentemente dal fatto che lo confronterai con qualcos'altro o no.
DiegoDD,

67

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

Ciò che ottieni !!è la capacità di verificare la veridicità di più variabili l'una contro l'altra in modo ripetibile, standardizzato (e compatibile con JSLint).

Semplicemente casting :(

Questo è...

  • 0 === falselo è false.
  • !!0 === falselo è 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 lanciare una variabile in booleano e poi confrontarla con un "vero" booleano.

Vedi "== e! =" Dalle indicazioni di JSLint (nota: Crockford sta spostando un po 'il suo sito; quel collegamento rischia di morire ad un certo punto) per un po' del perché:

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

Se ti interessa solo che un valore sia veritiero o falso, usa la forma abbreviata. Invece di
(foo != 0)

basta dire
(foo)

e invece di
(foo == 0)

dire
(!foo)

Nota che ci sono alcuni casi non intuitivi in cui un booleano verrà lanciato su un numero ( trueviene lanciato su 1e falseverso 0) quando si confronta un booleano con un numero. In questo caso, !!potrebbe essere mentalmente utile. Anche se, di nuovo, questi sono casi in cui stai confrontando un non booleano con un booleano duro, 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());

A causa di alcuni jive di Windows storici , verrà visualizzato -1 in una finestra di messaggio! Provalo nel prompt di cmd.exe e guarda! Ma WScript.echo(-1 == test())ti dà ancora 0, o WScript false. Distogliere lo sguardo. È orribile.

Confrontando la verità :)

Ma cosa succede se ho due valori che devo verificare per uguale truthi / falsità?

Fai finta di avere myVar1 = 0;e myVar2 = undefined;.

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

Quindi l'unico posto in cui avresti davvero bisogno di usare "variabili booleane cast" sarebbe se avessi una situazione in cui stai controllando se entrambe le variabili hanno la stessa veridicità, giusto? Cioè, usa !!se hai bisogno di vedere se due vars sono entrambi veritieri o entrambi falsi (o no), cioè di uguale (o no) verità .

Non riesco a pensare a un caso d'uso eccezionale e non inventato per questo fuori mano. Forse hai campi "collegati" in un modulo?

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 extra sulla tua errorObjectscollezione.


MODIFICA 24 ott 2017, 6 febbraio 19:

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.

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

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

... potresti essere sorpreso di vedere React render a 0quando hai zero messaggi. Devi restituire esplicitamente false per non eseguire il rendering di JSX. Restituisce la precedente dichiarazione 0, che JSX rende felicemente, come dovrebbe. Non posso dire che non hai avuto Count: {messageCount && <div>Get your count to zero!</div>}(o qualcosa di meno inventato).

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

  • I documenti di JSX suggeriscono di essere più espliciti, scrivere codice di auto-commento e utilizzare un confronto per forzare un valore booleano.
    {messageCount > 0 && <div>You have messages!</div>}

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

Stesso affare in Typescript: se hai una funzione che restituisce un valore booleano (o stai assegnando un valore a una variabile booleana), [di solito] non puoi restituire / assegnare un valore booleano-y; deve essere un booleano fortemente tipizzato. Questo significa che, se if myObjectè fortemente tipizzato , return !myObject;funziona per una funzione che restituisce un valore booleano, ma return myObject;non lo fa. Devi return !!myObjectsoddisfare le aspettative di Typescript.

L'eccezione per Typescript? Se myObjectera un any, sei tornato nel selvaggio West di JavaScript e puoi restituirlo senza !!, anche se il tuo tipo di ritorno è un valore booleano.

Tieni presente che si tratta di convenzioni JSX e Typescript , non inerenti a JavaScript .

Ma se vedi strani 0s nel tuo JSX renderizzato, pensa alla falsa gestione.


Buona spiegazione Quindi diresti !! non è strettamente necessario in questo esempio di rilevamento della funzionalità di lavoro ? if (!!window.Worker)
jk7,

2
No, non ne avresti bisogno. Verità e true"esternamente" operano esattamente allo stesso modo in un if. Continuo a provare, ma non riesco a pensare a un motivo per preferire lanciare la verità a un valore booleano al di fuori del tipo di caso contorto "confronta verità", sopra, fatta eccezione per la leggibilità se riutilizzi il valore in un secondo momento, come nell'esempio della qbiblioteca . Ma anche in questo caso, è una scorciatoia con perdita di informazioni, e direi che è meglio valutare ogni volta la veridicità.
ruffin,

React è il motivo principale per cui abbiamo iniziato a usare !! modello, ma sembra essere una cosa molto conveniente e ripetibile. Devo solo preoccuparmi della veridicità o falsità di qualcosa, non di quale sia il tipo sottostante.

Downvotes senza commenti rendono difficile rispondere alle tue preoccupazioni! Fammi sapere cosa sembra male e sarò felice di affrontarlo.
ruffin,

55

È solo l'operatore NOT logico, due volte: viene utilizzato per convertire qualcosa in booleano, ad esempio:

true === !!10

false === !!0

3
Perché mai lo faresti? Usa il ! operatore per convertire in booleano quindi utilizzare === per confrontare il tipo? Accetta semplicemente che non hai la sicurezza del tipo e fai val> 0 o qualcosa del genere.
Darren Clark,

43
@Darren: non sta confrontando i tipi; ti sta dicendo quali sono i risultati, scrivendo affermazioni nella sua risposta.
Razze di leggerezza in orbita


26

È una doppia notoperazione. Il primo !converte il valore in booleano e inverte il suo valore logico. Il secondo !inverte il valore logico indietro.


26

Sembra che l' !!operatore si traduca in una doppia negazione.

var foo = "Hello World!";

!foo // Result: false
!!foo // Result: true

23

Simula il comportamento della Boolean()funzione di casting. Il primo NOTrestituisce un valore booleano, indipendentemente dall'operando che viene fornito. Il secondo NOTnega quel Booleanvalore e quindi fornisce il truevalore booleano di una variabile. Il risultato finale è uguale all'utilizzo della Boolean()funzione su un valore.


20

! è "non booleano", che essenzialmente scrive il valore di "abilita" al suo opposto booleano. Il secondo ! lancia questo valore. Quindi, !!enablesignifica "non abilitare", dandoti il ​​valore di enablecome un valore booleano.


18

Penso che sia degno di nota che una condizione combinata con AND logico non restituirà un valore booleano ma l'ultimo successo o il primo fallimento in caso di && e il primo successo o l'ultimo fallimento in caso di || della catena delle condizioni.

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

Per assegnare la condizione a un vero letterale booleano possiamo usare la doppia negazione:

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

17

!!sta usando l' NOToperazione due volte insieme, !converti il ​​valore in a booleane lo inverte, ecco un semplice esempio per vedere come !!funziona:

All'inizio, il posto che hai:

var zero = 0;

Quindi lo fai !0, verrà convertito in booleano e verrà valutato in true, perché lo è 0 falsy, quindi ottieni il valore invertito e convertito in booleano, quindi viene valutato true.

!zero; //true

ma non vogliamo la versione booleana inversa del valore, quindi possiamo invertirla di nuovo per ottenere il nostro risultato! Ecco perché ne usiamo un altro !.

Fondamentalmente, !!assicuriamoci, il valore che otteniamo è booleano, non falso, verità o stringa ecc ...

Quindi è come usare la Booleanfunzione in javascript, ma un modo semplice e breve per convertire un valore in booleano:

var zero = 0;
!!zero; //false

15

Il !!costrutto è un modo semplice di trasformare qualsiasi espressione JavaScript nel suo equivalente booleano.

Ad esempio: !!"he shot me down" === truee !!0 === false.


2
Molto vicino all'importante distinzione. La chiave è che 0 === falseè falso ed !!0 === falseè vero.
ruffin,

14

Non è un singolo operatore, è due. È equivalente al seguente ed è un modo rapido per lanciare un valore in booleano.

val.enabled = !(!enable);

10

Sospetto che questo sia un residuo del C ++ in cui le persone hanno la precedenza su! operatore ma non l'operatore bool.

Quindi per ottenere una risposta negativa (o positiva) in quel caso dovresti prima usare il! operatore per ottenere un valore booleano, ma se si desidera verificare il caso positivo si userebbe !!.


10

La ife whilele dichiarazioni ed i ?valori di utilizzo di verità operatore per determinare quale ramo di codice da eseguire. Ad esempio, i numeri zero e NaN e la stringa vuota sono falsi, ma altri numeri e stringhe sono veri. Gli oggetti sono veri, ma il valore non definito ed nullentrambi sono falsi.

L'operatore doppia negazione !!calcola il valore di verità di un valore. In realtà sono due operatori, dove !!xsignifica !(!x), e si comportano come segue:

  • Se xè un valore falso, !xè truee !!xè false.
  • Se xè un valore vero, !xè falsee !!xè true.

Quando viene utilizzato al livello superiore di un contesto booleano ( if, whileo ?), l' !!operatore è comportamentale un no-op. Ad esempio, if (x)e if (!!x)significano la stessa cosa.

Usi pratici

Tuttavia ha diversi usi pratici.

Un uso è comprimere in perdita un oggetto al suo valore di verità, in modo che il codice non mantenga un riferimento a un oggetto grande e lo mantenga in vita. L'assegnazione !!some_big_objecta una variabile invece di some_big_objectlasciarla andare per il Garbage Collector. Ciò è utile per i casi che producono un oggetto o un valore falso come nullo il valore indefinito, come il rilevamento delle funzionalità del browser.

Un altro uso, di cui ho parlato in un risposta su corrispondente di C !!dell'operatore , è con "pelucchi" strumenti quello sguardo per errori di battitura comuni e la diagnostica di stampa. Ad esempio, sia in C che in JavaScript, alcuni errori di battitura comuni per le operazioni booleane producono altri comportamenti il ​​cui output non è proprio booleano:

  • if (a = b)è il compito seguito dall'uso del valore di verità di b; if (a == b)è un confronto di uguaglianza.
  • if (a & b)è un AND bit a bit; if (a && b)è un AND logico. 2 & 5è 0(un valore falso); 2 && 5è vero.

L' !!operatore rassicura lo strumento lanugine che ciò che hai scritto è ciò che intendevi: fai questa operazione, quindi prendi il valore di verità del risultato.

Un terzo uso è produrre XOR logico e XNOR logico. In C e JavaScript, a && besegue un AND logico (vero se entrambi i lati sono veri) ed a & besegue un AND bit per bit. a || besegue un OR logico (vero se almeno uno è vero) ed a | besegue un OR bit per bit. C'è un XOR bit a bit (OR esclusivo) come a ^ b, ma non c'è un operatore incorporato per XOR logico (vero se esattamente un lato è vero). Ad esempio, potresti voler consentire all'utente di inserire il testo esattamente in uno dei due campi. Che cosa si può fare è convertire ciascuno per un valore di verità e confrontarli: !!x !== !!y.


8

Doppia negazione booleana. Spesso utilizzato per verificare se il valore non è indefinito.


8

Tonnellate di ottime risposte qui, ma se hai letto fino a questo punto, questo mi ha aiutato a "ottenerlo". Apri la console su Chrome (ecc.) E inizia a digitare:

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

Naturalmente, sono tutti uguali al semplice digitare !! someThing, ma le parentesi aggiunte potrebbero aiutare a renderlo più comprensibile.


8

!!x è una scorciatoia per Boolean(x)

Il primo botto costringe il motore js a funzionare Boolean(x)ma ha anche l'effetto collaterale di invertire il valore. Quindi il secondo botto annulla l'effetto collaterale.


8

Costringe tutte le cose a booleane.

Per esempio:

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

7

A questa domanda è stata data una risposta abbastanza approfondita, ma vorrei aggiungere una risposta che spero sia il più semplice possibile, dando il significato di !! il più semplice da afferrare possibile.

Poiché JavaScript ha i cosiddetti valori "verità" e "falsità", ci sono espressioni che quando valutate in altre espressioni si tradurrà in una condizione vera o falsa, anche se il valore o l'espressione che si sta esaminando non sono effettivamente trueo false.

Per esempio:

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

Se tale elemento esiste, l'espressione verrà valutata come vera e verrà eseguito il blocco di codice.

Però:

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

... NON si tradurrà in una condizione vera e il blocco di codice non verrà eseguito, anche se l'elemento esiste.

Perché? Perché document.getElementById()è un'espressione "veritiera" che valuterà come vera in questa if()affermazione, ma non è un valore booleano reale di true.

Il doppio "non" in questo caso è abbastanza semplice. Sono semplicemente due notsecondi.

Il primo semplicemente "inverte" il valore di verità o falsità, risultando in un tipo booleano reale, e poi il secondo "lo inverte" di nuovo al suo stato originale, ma ora in un valore booleano reale. In questo modo hai coerenza:

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

e

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

ENTRAMBI restituiranno true, come previsto.


7

Volevo solo aggiungerlo

if(variableThing){
  // do something
}

equivale a

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

Ma questo può essere un problema quando qualcosa non è definito.

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

Il trucco qui è che la catena di &&s restituirà il primo valore di falsità che trova - e questo può essere alimentato a un'istruzione if ecc. Quindi, se b.foo non è definito, tornerà indefinito e salterà l' b.foo.baraffermazione, e non otteniamo alcun errore.

Quanto sopra restituito non definito, ma se si dispone di una stringa vuota, false, null, 0, indefinito, questi valori torneranno e non appena li incontreremo nella catena - []e {}sono entrambi "veritieri" e continueremo lungo il cosiddetto " && chain "al valore successivo a destra.

PS Un altro modo di fare la stessa cosa è (b || {}).foo, perché se b non è definito, b || {}lo sarà {}, e accederai a un valore in un oggetto vuoto (nessun errore) invece di provare ad accedere a un valore all'interno di "undefined" (causa un errore ). Quindi, (b || {}).fooè lo stesso di b && b.fooed ((b || {}).foo || {}).barè lo stesso di b && b.foo && b.foo.bar.


buon punto - ha cambiato la mia risposta. Succede solo su un oggetto quando è annidato a tre livelli di profondità, perché come hai detto ({}).anythingdaraiundefined
Ryan Taylor

5

Dopo aver visto tutte queste grandi risposte, vorrei aggiungere un altro motivo per l'utilizzo !!. Attualmente sto lavorando in Angular 2-4 (TypeScript) e voglio restituire un valore booleano come falsequando il mio utente non è autenticato. Se non è autenticato, la stringa token sarebbe nullo "". Posso farlo usando il prossimo blocco di codice:

public isAuthenticated(): boolean {
   return !!this.getToken();
}

4

ecco un pezzo di codice da js angolare

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

 var rafSupported = !!requestAnimationFrame;

la loro intenzione è di impostare rafSupported su true o false in base alla disponibilità della funzione in requestAnimationFrame

può essere ottenuto controllando in generale il seguente modo:

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

il modo breve potrebbe essere usando !!

rafSupported = !!requestAnimationFrame ;

quindi se requestAnimationFrame è stata assegnata una funzione allora! requestAnimationFrame sarebbe falso e un altro! sarebbe vero

se requestAnimationFrame fosse valutato non definito allora requestAnimationFrame sarebbe vero e un altro! sarebbe falso


3

Alcuni operatori in JavaScript eseguono conversioni di tipo implicito e talvolta vengono utilizzati per la conversione di tipo.

L' !operatore unario converte il suo operando in un valore booleano e lo annulla.

Questo fatto porta al seguente idioma che puoi vedere nel tuo codice sorgente:

!!x // Same as Boolean(x). Note double exclamation mark

3

Utilizzare l'operatore non logico due volte
significa! True = false
e !! true = true


3

Restituisce il valore booleano di una variabile.

Invece, la Booleanclasse può essere utilizzata.

(leggi le descrizioni dei codici)

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`

Vale Boolean(X) = !!Xa dire, in uso.

Controlla lo snippet di codice in basso

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.