Cuál es el !! (no no) operador en JavaScript?

3108

Vi un código que parece utilizar un operador que no reconozco, en forma de dos signos de exclamación, así: !!. ¿Alguien puede decirme qué hace este operador?

El contexto en el que vi esto fue,

this.vertical = vertical !== undefined ? !!vertical : this.vertical;
Teoría del hexágono
fuente
946
Recuérdalo por "bang, bang eres booleano"
Gus
75
Solo para que conste, no hagas lo que se cita allí. Hacer if(vertical !== undefined) this.vertical = Boolean(vertical);: es mucho más claro y claro lo que está sucediendo, no requiere una asignación innecesaria, es completamente estándar y es igual de rápido (en FF y Chrome actuales ) jsperf.com/boolean-conversion-speed .
Phil H
73
!! No es un operador. ¡Es solo el! operador dos veces.
Vivek
11
Solo para que conste, Boolean(5/0)no es lo mismo que!!5/0
schabluk
63
@schabluk, para el registro, el orden de las operaciones es la razón que !!5/0produce en Infinitylugar de true, según lo producido por Boolean(5/0). !!5/0es equivalente a (!!5)/0- aka true/0- debido a que el !operador tiene mayor prioridad que el /operador. Si quisieras Booleanizar 5/0usando un doble golpe, deberías usarlo !!(5/0).
Matty

Respuestas:

2749

Convierte Objecta boolean. Si era Falsey (por ejemplo 0, null, undefined, etc.), será false, de lo contrario, true.

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

Entonces !!no es un operador, es solo el !operador dos veces.

Ejemplo del mundo real "Versión de prueba de IE":

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

Si ⇒

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

Pero si ⇒

console.log(!!navigator.userAgent.match(/MSIE 8.0/));  
// returns either true or false
stevehipwell
fuente
123
Convierte un valor no booleano en un valor booleano invertido (por ejemplo,! 5 sería falso, ya que 5 es un valor no falso en JS), luego lo convierte en un valor booleano (entonces !! 5 sería ser cierto).
Chuck el
111
Una manera fácil de describirlo es: Boolean (5) === !! 5; Mismo casting, menos personajes.
Micah Snyder
39
Esto se utiliza para convertir los valores de verdad en booleano verdadero, y los valores de falsedad también booleano falso.
thetoolman
13
@Micah Snyder tenga cuidado de que en JavaScript es mejor usar primitivas booleanas en lugar de crear objetos que boxeen booleanos con un nuevo Boolean (). Aquí hay un ejemplo para ver la diferencia: jsfiddle.net/eekbu
victorvartan
44
Hasta donde sé, este patrón bang-bang no es útil dentro de una declaración if (... _; solo en una declaración return de una función que debería devolver un valor booleano.
rds
854

Es una forma horriblemente oscura de hacer una conversión de tipo.

!es NO . Así !truees falsey !falsees true. !0es true, y !1es false.

Entonces estás convirtiendo un valor en un booleano, luego lo inviertes y luego lo vuelves a invertir.

// 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
fuente
74
!! falso = falso. !! verdadero = verdadero
cllpse
89
¿La variante "mucho más fácil de entender" es realmente mucho más fácil de entender aquí? La verificación contra 0 no es una verificación real contra 0, pero una verificación contra la extraña lista de valores que Javascript considera igual a 0. userId ? true : false deja más claro que hay una conversión en curso y maneja el caso en el que el valor de userId podría haberse establecido explícitamente enundefined
Ben Regenspan
54
Mi cerebro no tiene ningún problema decodificación !!varen Boolean(var).. y !!es más rápido (menos instrucciones para procesar) y más cortas que las alternativas.
adamJLev
77
@RickyClarkson es principalmente para facilitar la lectura, ya que sintácticamente no es necesario. Algunos usan la convención de siempre envolver un condicional entre paréntesis para diferenciarlo del resto de la expresión.
Dave Rager
8
No estoy de acuerdo con esto. userId != 0es verdadero para null, NaNy undefined, pero falso para false. Si desea exactamente ese comportamiento, probablemente debería ser explícito al respecto. Pero incluso si funcionó exactamente igual !!userId, no está claro si desea que esos valores salgan falsos aquí, o si simplemente no tuvo en cuenta las reglas de conversión de tipos de Javascript.
philh
449

!!exprdevuelve un valor booleano ( trueo false) según la veracidad de la expresión. Tiene más sentido cuando se usa en tipos no booleanos. Considere estos ejemplos, especialmente el 3er ejemplo y en adelante:

          !!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
fuente
63
Vale la pena señalar:!!new Boolean(false) // true
Camilo Martin
43
... Pero también!!Boolean(false) // false
Camilo Martin
97
new Boolean(false)es un objeto y un objeto es verdadero incluso si contiene un valor falso.
Salman A
3
Sí, lo sé, pero considero que el hecho de que la mayoría de los constructores nativos ( String, Number, Date, etc.) están destinados a ser exigible como funciones también, sin embargo, en este caso el resultado es diferente!
Camilo Martin
44
@CamiloMartin: acabo de darme cuenta de que new Boolean(false)devuelve un objecttiempo Boolean(false)devuelve lo primitivo false . Espero que esto tenga sentido.
Salman A
155

Prepara un poco de té:

!!No es un operador. Es el doble uso de !, que es el operador lógico "no".


En teoria:

! determina la "verdad" de lo que no es un valor:

  • La verdad es que falseno lo es true(por eso !falseresulta true)

  • La verdad es que trueno lo es false(por eso !trueresulta false)


!!determina la "verdad" de lo que un valor no es:

  • La verdad es que trueno es así true (por eso !!trueresulta true)

  • La verdad es que falseno es así false (por eso !!falseresulta false)


Lo que deseamos determinar en la comparación es la "verdad" sobre el valor de una referencia, no el valor de la referencia en sí. Hay un caso de uso en el que podríamos querer saber la verdad sobre un valor, incluso si esperamos que el valor sea false(o falsey), o si esperamos que el valor no sea typeof boolean.


En la práctica:

Considere una función concisa que detecta la funcionalidad de la característica (y en este caso, la compatibilidad de la plataforma) a través de la escritura dinámica (también conocida como "escritura de pato"). Queremos escribir una función que regrese truesi el navegador de un usuario admite el <audio>elemento HTML5 , pero no queremos que la función arroje un error si <audio>no está definida; y no queremos usar try ... catchpara manejar posibles errores (porque son asquerosos); y tampoco queremos usar una verificación dentro de la función que no revelará constantemente la verdad sobre la función (por ejemplo, document.createElement('audio')seguirá creando un elemento llamado <audio>incluso si HTML5 <audio>no es compatible).


Aquí están los tres enfoques:

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

Cada función acepta un argumento para a <tag>y an attributepara buscar, pero cada uno devuelve valores diferentes en función de lo que determinan las comparaciones.

¡Pero espera hay mas!

Algunos de ustedes probablemente notaron que en este ejemplo específico, uno simplemente podría verificar una propiedad utilizando los medios ligeramente más eficaces para verificar si el objeto en cuestión tiene una propiedad. Hay dos maneras de hacer esto:

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

Estamos divagando ...

Por muy raras que puedan ser estas situaciones, puede haber algunos escenarios en los que el medio más conciso, más eficaz y, por lo tanto, el más preferido para obtener trueun valor no booleano, posiblemente indefinido, es el uso !!. Esperemos que esto lo aclare ridículamente.

Benny
fuente
1
respuesta totalmente increíble, pero no veo la utilidad de la !! construir. Dado que una if()declaración ya convierte la expresión en booleana, la conversión explícita del valor de retorno de una función de prueba a booleana es redundante, ya que "veracidad" === verdadero hasta donde if()llega una declaración de todos modos. ¿O me estoy perdiendo un escenario en el que NECESITAS que una expresión de verdad sea realmente booleana true?
Tom Auger
1
Las if()declaraciones de @TomAuger emiten valores booleanos contra valores de falsey, pero dicen que realmente desea establecer una bandera booleana en un objeto; no lo emitirá como lo hace una if()declaración. Por ejemplo object.hasTheThing = !!castTheReturnValToBoolNoMatterWhat(), establecería cualquiera trueo en falselugar del valor de retorno real. Otro ejemplo es que tal vez todos los administradores son idde 0y los no administradores son id 1o superior. Para obtener truesi alguien no es un administrador que podría hacer person.isNotAdmin = !!admin.id. Pocos casos de uso, pero es conciso cuando lo hay.
Benny
103

!!convierte el valor a su derecha en su valor booleano equivalente. (Piense en la forma de "fundición de tipos" del pobre). Por lo general, su intención es transmitir al lector que al código no le importa qué valor tiene la variable, sino cuál es su valor de "verdad" .

Creciente Fresco
fuente
44
O en el caso de un valor booleano a la derecha, no hace nada.
Daniel A. White
3
@Daniel: !todavía voltea el valor a la derecha. En el caso de un booleano, el extremo derecho !niega el valor, mientras que el !extremo izquierdo lo niega una vez más. El efecto neto es que no hay cambios, pero la mayoría de los motores generarán códigos operativos para la doble negación.
Crescent Fresh
¿Pero cuál es el punto? Si hago if(0){...Javascript ya sabe que esto es falso. ¿Por qué es mejor decirlo if(!!0){...?
CodyBugstein
el punto es para variables que quizás no conozcas su contenido; si podría ser un entero o una cadena, un objeto o un valor nulo, indefinido, etc. Esta es una manera fácil de probar la existencia.
mix3d
71

!!fooaplica el operador no unario dos veces y se utiliza para convertir a tipo booleano similar al uso de unario más +foopara convertir a número y concatenando una cadena vacía ''+foopara convertir a cadena.

En lugar de estos hacks, también puede usar las funciones de constructor correspondientes a los tipos primitivos ( sin usar new) para emitir valores explícitamente, es decir

Boolean(foo) === !!foo
Number(foo)  === +foo
String(foo)  === ''+foo
Christoph
fuente
Pero luego puede encontrarse con problemas con instanceof. nueva instancia booleana (1) de objeto -> verdadero !! 1 instancia de objeto -> falso
Seamus
13
no, no puede: observe que las funciones del constructor se llaman sin new, como se menciona explícitamente en mi respuesta
Christoph el
2
¡fantástico! Esto es útil para un pequeño truco cuando necesita evaluar cadenas con "0" como falso en lugar de verdadero. (es decir, al leer valores de selecciones, porque se leen como Cadena). Entonces, si desea considerar "0" como negativo (falso booleano), suponiendo x="0"simplemente hacer: x=!!+x; //falseque es lo mismo que Boolean(Number(x))Número (o + x) convierte la cadena "0" a 0, que SÍ evalúa a falso, y luego Booleano (!! x) lo convierte en booleano directamente. ¡Pan comido!
DiegoDD
2
@DiegoDD ¿por qué elegirías !!+xvs x !== "0"?
placeybordeaux
@placeybordeaux porque, por ejemplo, es posible que desee convertir el valor y asignarlo a otra variable, independientemente de si lo va a comparar con otra cosa o no.
DiegoDD
67

Tantas respuestas haciendo la mitad del trabajo. Sí, !!Xpodría leerse como "la veracidad de X [representada como booleana]". Pero !!, en términos prácticos, no es tan importante para determinar si una sola variable es (o incluso si muchas variables son) verdadera o falsa. !!myVar === truees lo mismo que simplemente myVar. Comparar !!Xun booleano "real" no es realmente útil.

Con lo que se gana !!es con la capacidad de verificar la veracidad de múltiples variables entre sí de manera repetible, estandarizada (y amigable con JSLint).

Simplemente casting :(

Es decir...

  • 0 === falsees false.
  • !!0 === falsees true.

Lo anterior no es tan útil. if (!0)te da los mismos resultados que if (!!0 === false). No puedo pensar en un buen caso para convertir una variable en booleana y luego compararla con una booleana "verdadera".

Vea "== y! =" En las instrucciones de JSLint (nota: Crockford está moviendo su sitio un poco; ese enlace puede morir en algún momento) por un poco sobre por qué:

Los operadores == y! = Escriben la coerción antes de comparar. Esto es malo porque hace que '\ t \ r \ n' == 0 sea verdadero. Esto puede enmascarar errores de tipo. JSLint no puede determinar de manera confiable si == se está utilizando correctamente, por lo que es mejor no usar == y! = En absoluto y usar siempre los operadores === y! == más confiables.

Si solo le importa que un valor sea verdadero o falso, utilice la forma abreviada. En vez de
(foo != 0)

sólo decir
(foo)

y en lugar de
(foo == 0)

decir
(!foo)

Tenga en cuenta que hay algunos casos poco intuitivos en los que un booleano se convertirá en un número ( truese convierte en 1y falsepara 0) al comparar un booleano con un número. En este caso, !!podría ser mentalmente útil. Sin embargo, de nuevo, estos son casos en los que se compara un booleano no booleano con un booleano de tipo rígido, lo cual es un error grave. if (-1)sigue siendo el camino a seguir aquí.

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

Y las cosas se ponen aún más locas dependiendo de tu motor. WScript, por ejemplo, gana el premio.

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

¡Debido a algunos cambios históricos de Windows , eso generará -1 en un cuadro de mensaje! ¡Pruébelo en un indicador de cmd.exe y vea! Pero WScript.echo(-1 == test())aún así te da 0, o WScript false. Apartar. Es horrible

Comparando la veracidad :)

Pero, ¿qué pasa si tengo dos valores que necesito verificar para verdades / falsidades iguales?

Finge que tenemos myVar1 = 0;y myVar2 = undefined;.

  • myVar1 === myVar2es 0 === undefinedy es obviamente falso.
  • !!myVar1 === !!myVar2es !!0 === !!undefinedy es verdad! La misma veracidad! (En este caso, ambos "tienen una verdad de falsedad").

Entonces, el único lugar en el que realmente necesitaría usar "variables de conversión booleana" sería si tuviera una situación en la que esté verificando si ambas variables tienen la misma veracidad, ¿verdad? Es decir, el uso !!si es necesario para ver si son dos vars tanto Truthy o ambos Falsy (o no), es decir, de igual (o no) truthiness .

No puedo pensar en un gran caso de uso no ideado para esa mano abierta. ¿Quizás tiene campos "vinculados" en un formulario?

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

Entonces, si tiene una verdad para ambos o una falsa para el nombre y la edad del cónyuge, puede continuar. De lo contrario, solo tiene un campo con un valor (o un matrimonio arreglado muy temprano) y necesita crear un error adicional en su errorObjectscolección.


EDITAR 24 oct 2017, 6 feb 19:

Bibliotecas de terceros que esperan valores booleanos explícitos

Aquí hay un caso interesante ... !!podría ser útil cuando las bibliotecas de terceros esperan valores booleanos explícitos.

Por ejemplo, False en JSX (React) tiene un significado especial que no se desencadena en la falsedad simple. Si intentó devolver algo como lo siguiente en su JSX, esperando un int en messageCount...

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

... es posible que se sorprenda al ver que React se procesa 0cuando tiene cero mensajes. Debe devolver explícitamente false para que JSX no se procese. La declaración anterior regresa 0, que JSX representa felizmente, como debería. No se puede decir que no tenía Count: {messageCount && <div>Get your count to zero!</div>}(o algo menos artificial).

  • Una solución consiste en la bangbang, que coacciona 0a !!0, que es false:
    {!!messageCount && <div>You have messages!</div>}

  • Los documentos de JSX sugieren que seas más explícito, que escribas un código de auto comentario y que uses una comparación para forzar un booleano.
    {messageCount > 0 && <div>You have messages!</div>}

  • Me siento más cómodo manejando la falsedad con un ternario.
    {messageCount ? <div>You have messages!</div> : false}

Mismo trato en Typecript: si tiene una función que devuelve un valor booleano (o está asignando un valor a una variable booleana), [generalmente] no puede devolver / asignar un valor booleano-y; Tiene que ser un booleano fuertemente tipado. Esto significa que si iff myObjectestá fuertemente tipado , return !myObject;funciona para una función que devuelve un valor booleano, pero return myObject;no lo hace. Tiene que return !!myObjectcoincidir con las expectativas de Typecript.

¿La excepción para el mecanografiado? Si myObjectfue un any, está de vuelta en el Salvaje Oeste de JavaScript y puede devolverlo sin !!, incluso si su tipo de retorno es booleano.

Tenga en cuenta que estas son convenciones JSX y mecanografiadas , no inherentes a JavaScript .

Pero si ve 0mensajes extraños en su JSX renderizado, piense en una gestión falsa.

ruffin
fuente
Buena explicación. Entonces dirías que el !! ¿No es estrictamente necesario en este ejemplo de detección de funciones de trabajador ? if (!!window.Worker)
jk7
2
No, no lo necesitarías. La verdad y true"externamente" operan exactamente igual en un if. Sigo intentándolo, pero no puedo pensar en una razón para preferir convertir la veracidad en un valor booleano fuera del tipo de caso complicado de "comparar verdades", arriba, excepto por la legibilidad si reutiliza el valor más tarde, como en el qejemplo de la biblioteca . Pero incluso entonces, es un acceso directo con pérdida de información, y diría que es mejor que evalúe la veracidad cada vez.
ruffin
¡Reaccionar es la razón principal por la que comenzamos a usar el !! patrón, pero resulta ser una cosa muy conveniente y repetible. Solo tengo que preocuparme por la veracidad o falsedad de algo, no por cuál es el tipo subyacente.
¡Los votos negativos sin comentarios hacen que sea difícil abordar su preocupación! Hágame saber qué se ve mal, y estaré encantado de abordarlo.
ruffin
55

Es solo el operador lógico NOT, dos veces: se usa para convertir algo a booleano, por ejemplo:

true === !!10

false === !!0
Greg
fuente
3
¿Por qué razón harías tú eso? Utilizar el ! operador para convertir a booleano y luego usar === para comparar el tipo? Solo acepta que no tienes ningún tipo de seguridad y haz val> 0 o algo así.
Darren Clark el
43
@Darren: Él no está comparando tipos; te dice cuáles son los resultados, escribiendo afirmaciones en su respuesta.
Carreras ligeras en órbita el
32

Convierte el sufijo en un valor booleano.

Paul McMillan
fuente
26

Es una doble notoperación. El primero !convierte el valor a booleano e invierte su valor lógico. El segundo !invierte el valor lógico de nuevo.

Bill el lagarto
fuente
26

Parece que el !!operador resulta en una doble negación.

var foo = "Hello World!";

!foo // Result: false
!!foo // Result: true
Steve Harrison
fuente
23

Simula el comportamiento de la Boolean()función de fundición. El primero NOTdevuelve un valor booleano sin importar qué operando se le dé. El segundo NOTniega ese Booleanvalor y, por lo tanto, da el truevalor booleano de una variable. El resultado final es el mismo que usar la Boolean()función en un valor.

Prakash
fuente
20

! es "no booleano", que esencialmente encasilla el valor de "habilitar" a su opuesto booleano. El segundo ! Voltea este valor. Entonces, !!enablesignifica "no habilitar", dándole el valor de enablecomo un booleano.

Annika Backstrom
fuente
18

Creo que vale la pena mencionar que una condición combinada con AND / OR lógico no devolverá un valor booleano, sino el último éxito o el primer error en el caso de && y el primer éxito o el último error en el caso de || de condición de cadena.

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

Para convertir la condición a un verdadero literal booleano, podemos usar la doble negación:

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

!!usa la NOToperación dos veces juntas, !convierte el valor a booleane inviertelo, aquí hay un ejemplo simple para ver cómo !!funciona

Al principio, el lugar que tienes:

var zero = 0;

Luego !0, se convertirá a booleano y se evaluará a true, porque 0 es falsy, por lo que obtiene el valor invertido y se convierte a booleano, por lo que se evalúa a true.

!zero; //true

pero no queremos la versión booleana invertida del valor, por lo que podemos invertirla nuevamente para obtener nuestro resultado. Por eso usamos otro !.

Básicamente, !!asegúrate de que el valor que obtenemos es booleano, no falso, verdadero o cadena, etc.

Entonces, es como usar la Booleanfunción en javascript, pero es una forma fácil y más corta de convertir un valor a booleano:

var zero = 0;
!!zero; //false
Alireza
fuente
15

La !!construcción es una forma simple de convertir cualquier expresión de JavaScript en su equivalente booleano.

Por ejemplo: !!"he shot me down" === truey !!0 === false.

Navin Rauniyar
fuente
2
Muy cerca de la distinción importante. La clave es que 0 === falsees falsa y !!0 === falsees verdadera.
ruffin
14

No es un solo operador, son dos. Es equivalente a lo siguiente y es una forma rápida de convertir un valor en booleano.

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

Sospecho que esto es un sobrante de C ++ donde la gente anula el! operador pero no el operador bool.

Por lo tanto, para obtener una respuesta negativa (o positiva) en ese caso, primero debe usar! operador para obtener un booleano, pero si quisieras marcar el caso positivo lo usarías !!.

Darren Clark
fuente
10

El ify whilelas declaraciones y los ?valores de uso de la verdad operador determinar qué rama de la ejecución de código. Por ejemplo, los números cero y NaN y la cadena vacía son falsos, pero otros números y cadenas son verdaderos. Los objetos son verdaderos, pero el valor indefinido y nullambos son falsos.

El operador de doble negación !!calcula el valor de verdad de un valor. En realidad, son dos operadores, donde !!xsignifica !(!x), y se comporta de la siguiente manera:

  • Si xes un valor falso, !xes truey !!xes false.
  • Si xes un valor verdadero, !xes falsey !!xes true.

Cuando se utiliza en el nivel superior de un contexto booleano ( if, whileo ?), el !!operador es conductualmente un no-op. Por ejemplo, if (x)y if (!!x)significa lo mismo.

Usos prácticos

Sin embargo, tiene varios usos prácticos.

Un uso es comprimir con pérdida un objeto a su valor de verdad, para que su código no tenga una referencia a un objeto grande y lo mantenga vivo. Asignación !!some_big_objecta una variable en lugar de some_big_objectsoltarla para el recolector de basura. Esto es útil para casos que producen un objeto o un valor falso como nullo el valor indefinido, como la detección de características del navegador.

Otro uso, que mencioné en una respuesta sobre el !!operador correspondiente de C , es con herramientas de "pelusa" que buscan errores tipográficos comunes y diagnósticos de impresión. Por ejemplo, tanto en C como en JavaScript, algunos errores tipográficos comunes para las operaciones booleanas producen otros comportamientos cuya salida no es tan booleana:

  • if (a = b)es la asignación seguida del uso del valor de verdad de b; if (a == b)Es una comparación de igualdad.
  • if (a & b)es un bit a bit Y; if (a && b)es un AND lógico. 2 & 5es 0(un valor falso); 2 && 5es verdad.

El !!operador asegura a la herramienta de pelusa que lo que escribió es lo que quiso decir: realice esta operación, luego tome el valor verdadero del resultado.

Un tercer uso es producir XOR lógico y XNOR lógico. Tanto en C como en JavaScript, a && brealiza un AND lógico (verdadero si ambos lados son verdaderos) y a & brealiza un AND bit a bit. a || brealiza un OR lógico (verdadero si al menos uno es verdadero) y a | brealiza un OR bit a bit. Hay un XOR bit a bit (OR exclusivo) como a ^ b, pero no hay un operador incorporado para XOR lógico (verdadero si exactamente un lado es verdadero). Es posible que, por ejemplo, desee permitir que el usuario ingrese texto en exactamente uno de los dos campos. Lo que puede hacer es convertir cada uno a un valor de verdad y ellos se compara: !!x !== !!y.

Damian Yerrick
fuente
8

Doble negación booleana. A menudo se usa para verificar si el valor no está indefinido.

Sergey Ilinsky
fuente
8

Toneladas de excelentes respuestas aquí, pero si has leído hasta aquí, esto me ayudó a 'entenderlo'. Abra la consola en Chrome (etc.) y comience a escribir:

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

Naturalmente, todo esto es lo mismo que simplemente escribir algo, pero los paréntesis adicionales pueden ayudar a que sea más comprensible.

Warren Davis
fuente
8

!!x es taquigrafía para Boolean(x)

La primera explosión fuerza al motor js a funcionar, Boolean(x)pero también tiene el efecto secundario de invertir el valor. Entonces, la segunda explosión deshace el efecto secundario.

Greg Gum
fuente
8

Obliga a todas las cosas a ser booleanas.

Por ejemplo:

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

Esta pregunta ha sido respondida a fondo, pero me gustaría agregar una respuesta que espero sea lo más simplificada posible, ¡lo que significa! tan simple de entender como puede ser.

Debido a que javascript tiene lo que se llama valores "veraces" y "falsey", existen expresiones que, cuando se evalúan en otras expresiones, darán como resultado una condición verdadera o falsa, aunque el valor o la expresión que se está examinando no sea realmente trueo false.

Por ejemplo:

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

Si ese elemento existe, la expresión se evaluará como verdadera y se ejecutará el bloque de código.

Sin embargo:

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

... NO dará como resultado una condición verdadera, y el bloque de código no se ejecutará, incluso si el elemento existe.

¿Por qué? Porque document.getElementById()es una expresión "veraz" que se evaluará como verdadera en esta if()declaración, pero no es un valor booleano real de true.

El doble "no" en este caso es bastante simple. Es simplemente dos notsegundos seguidos.

El primero simplemente "invierte" el valor verdadero o falso, dando como resultado un tipo booleano real, y luego el segundo "lo invierte" nuevamente a su estado original, pero ahora en un valor booleano real. De esa manera tienes consistencia:

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

y

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

AMBOS devolverá verdadero, como se esperaba.

Kirby L. Wallace
fuente
7

Solo quería agregar eso

if(variableThing){
  // do something
}

es lo mismo que

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

Pero esto puede ser un problema cuando algo no está definido.

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

El truco aquí es que la cadena de &&s devolverá el primer valor de falsey que encuentre, y esto se puede alimentar a una declaración if, etc. Así que si b.foo no está definido, volverá indefinido y omitirá la b.foo.bardeclaración, y no obtendremos error.

Los valores anteriores devuelven indefinidos, pero si tiene una cadena vacía, falsa, nula, 0, indefinida, esos valores regresarán y tan pronto como los encontremos en la cadena, []y {}ambos sean "verdaderos" y continuaremos por el llamado " && encadena "al siguiente valor a la derecha.

PD Otra forma de hacer lo mismo es (b || {}).foo, porque si b está indefinido, entonces b || {}lo estará {}, y accederá a un valor en un objeto vacío (sin error) en lugar de intentar acceder a un valor dentro de "indefinido" (provoca un error ) Entonces, (b || {}).fooes lo mismo b && b.fooy ((b || {}).foo || {}).bares lo mismo que b && b.foo && b.foo.bar.

Ryan Taylor
fuente
Buen punto - cambió mi respuesta. Solo ocurre en un objeto cuando está anidado a tres niveles de profundidad, porque como dijiste ({}).anything, cederáundefined
Ryan Taylor
5

Después de ver todas estas excelentes respuestas, me gustaría agregar otra razón para usar !!. Actualmente estoy trabajando en Angular 2-4 (TypeScript) y quiero devolver un booleano como falsecuando mi usuario no está autenticado. Si no está autenticado, el token-string sería nullo "". Puedo hacer esto usando el siguiente bloque de código:

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

aquí hay un fragmento de código de angular js

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

 var rafSupported = !!requestAnimationFrame;

su intención es establecer rafSupported en verdadero o falso según la disponibilidad de la función en requestAnimationFrame

Se puede lograr comprobando de la siguiente manera en general:

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

el camino corto podría estar usando !!

rafSupported = !!requestAnimationFrame ;

así que si requestAnimationFrame se le asignó una función, ¡requestAnimationFrame sería falso y uno más! de eso sería cierto

si requestAnimationFrame fue asignado indefinido, ¡requestAnimationFrame sería verdadero y uno más! de eso sería falso

JeevanReddy Avanaganti
fuente
3

Algunos operadores en JavaScript realizan conversiones de tipo implícitas y, a veces, se utilizan para la conversión de tipo.

El !operador unario convierte su operando a un booleano y lo niega.

Este hecho lleva al siguiente modismo que puedes ver en tu código fuente:

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

Use el operador lógico no dos veces
, significa! Verdadero = falso
y !! verdadero = verdadero

Abhay Dixit
fuente
3

Devuelve el valor booleano de una variable.

En cambio, Booleanse puede usar la clase.

(lea las descripciones de los códigos)

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`

A saber, Boolean(X) = !!Xen uso.

Verifique el fragmento de código a continuación

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
fuente