Em JavaScript, por que “0” é igual a falso, mas quando testado por 'if', não é falso por si só?

232

O seguinte mostra que "0"é falso em Javascript:

>>> "0" == false
true

>>> false == "0"
true

Então, por que o seguinte é impresso "ha"?

>>> if ("0") console.log("ha")
ha
falta de polaridade
fonte
47
"0"é uma sequência e, como não está vazia, é avaliada como verdadeira.
Digital Plane
8
"0" === false [...] false
3
Confira a verdade do artigo de Angus Croll em javascript. javascriptweblog.wordpress.com/2011/02/07/…
timrwood 30/09
8
'0'==falsemas '0' não é um valor Falsey (sim Javascript pode ser estranho)
Linsey
5
@Linsey: A coisa toda "falsy" e "truth" só foi criada para explicar como os valores são convertidos em booleanos. Quando você compara dois valores com ==, eles nunca são convertidos em booleanos, portanto não se aplica. (As regras para a conversão parecem favorecer a conversão para números.)
millimoose

Respostas:

251

A razão é porque quando você faz explicitamente "0" == false, ambos os lados estão sendo convertidos em números, e , em seguida, a comparação é realizada.

Quando você faz if ("0") console.log("ha"):, o valor da sequência está sendo testado. Qualquer string não vazia é true, enquanto uma string vazia é false.

Igual (==)

Se os dois operandos não forem do mesmo tipo , o JavaScript os converterá e aplicará uma comparação estrita. Se um operando for um número ou um booleano , os operandos serão convertidos em números, se possível; caso contrário, se um operando for uma sequência , o outro operando será convertido em uma sequência, se possível. Se ambos os operandos são objetos , o JavaScript compara referências internas que são iguais quando os operandos se referem ao mesmo objeto na memória.

(Dos operadores de comparação na Mozilla Developer Network)

jdi
fonte
348

Tabelas exibindo o problema:

verdade se declaração

e == comparações de verdade de todos os tipos de objeto em javascript

Moral da história use === igualdade estrita exibindo sanidade

crédito de geração da tabela: https://github.com/dorey/JavaScript-Equality-Table

Joe
fonte
2
Faz muito mais sentido com outra ordem de valores gist.github.com/kirilloid/8165660 #
kirilloid
3
A partir de agora, se alguém disser que nunca usa operadores de comparação estritos, eu o enfrentarei com essas tabelas e o farei chorar. Ainda não tenho certeza se eu entendo o conceito de NaNembora. Quero dizer, typeof NaN // numbermas NaN === NaN // false, hum ...
Justus Romijn
4
Um amigo meu fez f.cl.ly/items/3b0q1n0o1m142P1P340P/javascript_equality.html - os mesmos gráficos acima, mas um pouco mais fácil de ler.
Lucy Bain
@JustusRomijn existem vários valores para representar NaN, então quando você está comparando 2 NaNs, eles têm valores diferentes (eu acho). Leia a primeira citação aqui .
31518 cychoi
4
Essas tabelas têm um erro. Nem ==nem ===operador para a [], {}, [[]], [0]e [1]valores não avaliam para true. Quero dizer [] == []e [] === []também falso.
Herbertusz
38

Está de acordo com as especificações.

12.5 A declaração if 
.....

2. Se ToBoolean (GetValue (exprRef)) for verdadeiro, então 
uma. Retorne o resultado da avaliação da primeira instrução.
3. Senão, 
....

ToBoolean, de acordo com as especificações, é

A operação abstrata ToBoolean converte seu argumento em um valor do tipo Booleano, de acordo com a Tabela 11:

E essa tabela diz isso sobre strings:

insira a descrição da imagem aqui

O resultado é falso se o argumento for a String vazia (seu comprimento é zero); caso contrário, o resultado é verdadeiro

Agora, para explicar por que "0" == falsevocê deve ler o operador de igualdade, que afirma que ele obtém seu valor da operação abstrata GetValue(lref)corresponde ao mesmo para o lado direito.

Que descreve esta parte relevante como:

se IsPropertyReference (V), então 
uma. Se HasPrimitiveBase (V) for falso, então get seja o método interno da [[Get]] base, caso contrário, deixe get
seja o método interno especial [[Get]] definido abaixo. 
b. Retorne o resultado de chamar o método interno get usando base como este valor e passando
GetReferencedName (V) para o argumento

Ou, em outras palavras, uma string tem uma base primitiva, que chama de volta o método get interno e acaba parecendo falsa.

Se você deseja avaliar coisas usando a operação GetValue ==, se você deseja avaliar usando o ToBoolean, use ===(também conhecido como operador de igualdade "estrito")

Incógnito
fonte
"a string has a primitive base, which calls back the internal get method and ends up looking false"Isso é verdade para todas as strings?
Aziz punjani
@Interstellar_Coder Section 8.12.3: [[Get]] (P)descreve como funciona. É verdade apenas para os casos em que a string é 0, pois realiza várias outras chamadas internas, resultando eventualmente em GetOwnPropertyque "o que quer que seja" seja uma propriedade de dados, que retornará todo esse valor. É por isso que "0" é falso e "blá" é verdadeiro. Confira alguns dos vídeos de Douglas Crockford no Yahoo developer theatre, ele descreve a "verdade" em JavaScript um pouco menos complexa do que eu. Se você entender o que "verdade" e "falsidade" significam, entenderá a resposta de Bobince imediatamente.
Incognito
1
Onde posso encontrar as especificações?
user985366
12

É no PHP que a string "0"é falsa (false quando usado no contexto booleano). No JavaScript, todas as cadeias não vazias são verdadeiras.

O truque é que, ==contra um booleano não é avaliado em um contexto booleano, ele é convertido em número e, no caso de strings feitas pela análise como decimal. Então você obtém Number em 0vez da veracidade booleana true.

Esse é realmente um pouco pobre de design de linguagem e é uma das razões pelas quais tentamos não usar o infeliz ==operador. Use em ===vez disso.

bobince
fonte
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
fonte
4

Suas aspas ao redor do texto 0tornam-no uma sequência, que é avaliada como verdadeira.

Remova as aspas e deve funcionar.

if (0) console.log("ha") 
Jason Gennaro
fonte
correto, não sobre como "fazê-lo funcionar", mas a pergunta é mais como "por que se comportou dessa maneira?"
nonopolarity
1

A expressão "if" testa a veracidade, enquanto a dupla é igual à equivalência independente do tipo. Uma string é sempre verdadeira, como outras pessoas apontaram aqui. Se o duplo igual estivesse testando ambos os operandos quanto à veracidade e depois comparando os resultados, você obteria o resultado que estava assumindo intuitivamente, ou seja ("0" == true) === true. Como Doug Crockford diz em seu excelente JavaScript: the Good Parts , "as regras pelas quais [== força os tipos de seus operandos] são complicadas e imemoráveis ​​... A falta de transitividade é alarmante". Basta dizer que um dos operandos é coagido a combinar com o outro e que "0" acaba sendo interpretado como um zero numérico,

Jollymorphic
fonte
1

== O operador de igualdade avalia os argumentos após convertê-los em números. Então seqüência zero "0" é convertido para o tipo de dados Número e boolean false é convertido em número 0. Assim,

"0" == false // true

O mesmo se aplica a `

false == "0" //true

=== A verificação rigorosa de igualdade avalia os argumentos com o tipo de dados original

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

O mesmo se aplica a

false === "0" // false

No

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

A String "0" não se compara a nenhum argumento, e a string é um valor verdadeiro até ou a menos que seja comparada com qualquer argumento. É exatamente como

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

Mas

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

`

Vishnu K. Panicker
fonte
1

Isso ocorre porque o JavaScript usa coerção de tipo em contextos booleanos e seu código

if ("0") 

será coagido a ser verdadeiro em contextos booleanos.

Existem outros valores reais em Javascript que serão coagidos a verdade em contextos booleanos e, portanto, executam o bloco 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
fonte