En JavaScript, ¿por qué "0" es igual a falso, pero cuando se prueba con 'if' no es falso por sí mismo?

232

Lo siguiente muestra que "0"es falso en Javascript:

>>> "0" == false
true

>>> false == "0"
true

Entonces, ¿por qué se imprime lo siguiente "ha"?

>>> if ("0") console.log("ha")
ha
nonopolaridad
fuente
47
"0"es una cadena y, como no está vacía, se evalúa como verdadera.
Avión digital
8
"0" === false [...] false
3
Echa un vistazo a la verdad del artículo de Angus Croll en javascript. javascriptweblog.wordpress.com/2011/02/07/…
timrwood
8
'0'==falsepero '0' no es un valor de falsey (sí, Javascript puede ser extraño)
Linsey
55
@Linsey: Todo el asunto de "falsedad" y "verdad" solo tenía la intención de explicar cómo los valores se convierten en booleanos. Cuando compara dos valores con ==, nunca se convierten en booleanos, por lo que no se aplica. (Las reglas para la conversión parecen favorecer la conversión a números)
Millimoose

Respuestas:

251

La razón es porque cuando lo haces explícitamente "0" == false, ambos lados se convierten en números, y luego se realiza la comparación.

Cuando lo hace:, if ("0") console.log("ha")el valor de la cadena se está probando. Cualquier cadena no vacía es true, mientras que una cadena vacía es false.

Igual (==)

Si los dos operandos no son del mismo tipo , JavaScript convierte los operandos y luego aplica una comparación estricta. Si cualquiera de los operandos es un número o un booleano , los operandos se convierten en números si es posible; de lo contrario, si cualquiera de los operandos es una cadena , el otro operando se convierte en una cadena si es posible. Si ambos operandos son objetos , entonces JavaScript compara referencias internas que son iguales cuando los operandos se refieren al mismo objeto en la memoria.

(De operadores de comparación en la red de desarrolladores de Mozilla)

jdi
fuente
348

Tablas que muestran el problema:

verdad si la declaración

y == comparaciones verdaderas de todos los tipos de objetos en javascript

Moraleja del uso de la historia === estricta igualdad que muestra cordura

crédito de generación de tablas: https://github.com/dorey/JavaScript-Equality-Table

Joe
fuente
2
Tiene mucho más sentido con otro orden de valores gist.github.com/kirilloid/8165660
kirilloid
3
De ahora en adelante, si alguien dice que nunca usa operadores de comparación estrictos, lo enfrentaré con estas tablas y lo haré llorar. Aún no estoy seguro si entiendo el concepto de NaNsin embargo. Quiero decir, typeof NaN // numberpero NaN === NaN // false, hmm ...
Justus Romijn
44
Un amigo mío hizo f.cl.ly/items/3b0q1n0o1m142P1P340P/javascript_equality.html , los mismos gráficos que el anterior, pero un poco más fáciles de leer.
Lucy Bain
@JustusRomijn hay varios valores para representar NaN, por lo que cuando se comparan 2 NaN, son de valores diferentes (supongo). Lea la primera cita aquí .
cychoi
44
Estas tablas tienen un error. Ni ==tampoco ===operador para el [], {}, [[]], [0]y [1]los valores no evalúan a verdadero. Quiero decir [] == []y [] === []también falso.
Herbertusz
38

Es de acuerdo a las especificaciones.

12.5 La declaración if 
.....

2. Si ToBoolean (GetValue (exprRef)) es verdadero, entonces 
a. Devuelve el resultado de evaluar la primera declaración.
3. De lo contrario, 
....

ToBoolean, según las especificaciones, es

La operación abstracta ToBoolean convierte su argumento a un valor de tipo booleano según la Tabla 11:

Y esa tabla dice esto sobre cadenas:

ingrese la descripción de la imagen aquí

El resultado es falso si el argumento es la cadena vacía (su longitud es cero); de lo contrario el resultado es verdadero

Ahora, para explicar por "0" == falsequé debería leer el operador de igualdad, que establece que su valor de la operación abstracta GetValue(lref)coincide con el lado derecho.

Que describe esta parte relevante como:

si IsPropertyReference (V), entonces 
a. Si HasPrimitiveBase (V) es falso, entonces vamos a ser el método interno de base [[Get]], de lo contrario, vamos a obtener
sea ​​el método interno especial [[Get]] definido a continuación. 
si. Devuelve el resultado de llamar al método interno get usando base como su valor, y pasando
GetReferencedName (V) para el argumento

O, en otras palabras, una cadena tiene una base primitiva, que vuelve a llamar al método interno get y termina pareciendo falso.

Si desea evaluar las cosas usando la operación GetValue use ==, si desea evaluar usando el ToBooleanuso, ===(también conocido como el operador de igualdad "estricto")

Incógnito
fuente
"a string has a primitive base, which calls back the internal get method and ends up looking false"¿Es esto cierto para todas las cadenas?
aziz punjani
@Interstellar_Coder Section 8.12.3: [[Get]] (P)describe cómo funciona. Es cierto solo para los casos en que la cadena es 0, ya que hace un montón de otras llamadas internas que finalmente resultan en GetOwnPropertyque "lo que sea" es una propiedad de datos, que luego devuelve todo ese valor. Es por eso que "0" es falso y "bla" es verdadero. Echa un vistazo a algunos de los videos de Douglas Crockford en el teatro de desarrolladores de Yahoo, él describe la "verdad" en JavaScript un poco menos complejo que yo. Si comprende lo que significa "verdad" y "falsedad", comprenderá la respuesta de Bobince de inmediato.
Incógnito
1
¿Dónde puedo encontrar la especificación?
user985366
12

Es PHP donde la cadena "0"es falsa (false-when-used-in-boolean-context). En JavaScript, todas las cadenas no vacías son verdaderas.

El truco es que ==contra un valor booleano no se evalúa en un contexto booleano, se convierte en número, y en el caso de cadenas que se realiza analizando como decimal. Entonces obtienes Number en 0lugar de la verdad booleana true.

Este es un diseño de lenguaje realmente pobre y es una de las razones por las que tratamos de no utilizar el desafortunado ==operador. Usar en su ===lugar.

bobince
fuente
7
// I usually do this:

x = "0" ;

if (!!+x) console.log('I am true');
else      console.log('I am false');

// Essentially converting string to integer and then boolean.
Thava
fuente
4

Sus comillas alrededor lo 0convierten en una cadena, que se evalúa como verdadera.

Elimine las comillas y debería funcionar.

if (0) console.log("ha") 
Jason Gennaro
fuente
correcto, no sobre cómo "hacer que funcione", sino que la pregunta es más como "¿por qué se comportó de esa manera?"
nonopolaridad
1

La expresión "if" prueba la veracidad, mientras que la prueba de doble igualdad para la equivalencia independiente del tipo. Una cadena siempre es verdadera, como han señalado otros aquí. Si el doble igual probara la veracidad de sus dos operandos y luego comparara los resultados, obtendría el resultado que suponía intuitivamente, es decir ("0" == true) === true. Como dice Doug Crockford en su excelente JavaScript: las partes buenas , "las reglas por las cuales [== coacciona los tipos de sus operandos] son ​​complicadas e inmemorables ... La falta de transitividad es alarmante". Es suficiente decir que uno de los operandos está forzado para coincidir con el otro, y que "0" termina siendo interpretado como un cero numérico,

Alegre
fuente
1

== El operador de igualdad evalúa los argumentos después de convertirlos a números. Entonces la cadena cero "0" se convierte al tipo de datos Number y boolean false se convierte al Número 0. Entonces

"0" == false // true

Lo mismo se aplica a `

false == "0" //true

=== La estricta verificación de igualdad evalúa los argumentos con el tipo de datos original

"0" === false // false, because "0" is a string and false is boolean

Lo mismo se aplica a

false === "0" // false

En

if("0") console.log("ha");

La cadena "0" no se compara con ningún argumento, y la cadena es un valor verdadero hasta que, o a menos que se compare con algún argumento. Es exactamente como

if(true) console.log("ha");

Pero

if (0) console.log("ha"); // empty console line, because 0 is false

``

Vishnu K. Panicker
fuente
1

Esto se debe a que JavaScript usa la coerción de tipo en contextos booleanos y su código

if ("0") 

será forzado a verdadero en contextos booleanos.

Hay otros valores de verdad en Javascript que se convertirán en verdaderos en contextos booleanos y, por lo tanto, ejecutarán el bloque if:

if (true)
if ({})
if ([])
if (42)
if ("0")
if ("false")
if (new Date())
if (-42)
if (12n)
if (3.14)
if (-3.14)
if (Infinity)
if (-Infinity)
Sachin
fuente