Por que `null> = 0 && null <= 0` mas não` null == 0`?


142

Eu tive que escrever uma rotina que incrementa o valor de uma variável em 1 se seu tipo é numbere atribui 0 à variável, se não, onde a variável é inicialmente nullou undefined.

A primeira implementação foi v >= 0 ? v += 1 : v = 0porque pensei que qualquer coisa que não fosse um número tornaria uma expressão aritmética falsa, mas estava errada, pois null >= 0é avaliada como verdadeira. Aprendi então que nullse comporta como 0 e as seguintes expressões são avaliadas como verdadeiras.

  • null >= 0 && null <= 0
  • !(null < 0 || null > 0)
  • null + 1 === 1
  • 1 / null === Infinity
  • Math.pow(42, null) === 1

Obviamente, nullnão null == 0é 0. é avaliado como falso. Isso torna a expressão aparentemente tautológica (v >= 0 && v <= 0) === (v == 0)falsa.

Por que é nullcomo 0, embora não seja realmente 0?


3
Ele está falando sobre Javascript. Seu exemplo está em PHP. No operador PHP == compara valores de uma maneira especial. Você pode fazer algumas comparações realmente loucas, como "10" == "1e1" (o que é verdade). Se você usasse operador ===, obteria um resultado totalmente diferente porque verifica se o tipo corresponde e também o valor. Confira neste link out: php.net/manual/en/language.operators.comparison.php
Pijusn

O operador PHP '==' realmente funciona de uma maneira "especial".
Alquimista de dois bits

Se a sua exigência era para iniciar a contagem a 1 em vez de 0, há uma maneira muito concisa para contadores de incremento que são inicialmente quer nullou undefined:c = -~c // Results in 1 for null/undefined; increments if already a number
Ates Goral

1
undefinedé um valor variável, para variáveis ​​que não foram inicializadas. null, por outro lado, é um valor de objeto vazio e não deve ser misturado com números. nullnão deve ser combinado com números; portanto, nulo não deve ter que se comportar como números.
Matthew

1
@AtesGoral - conciso, mas não óbvio. Vale lembrar às pessoas que, sempre que fizerem algo não óbvio, adicione um comentário explicando o que o código faz. Na maioria das situações, eu consideraria uma "otimização prematura", uma vez que troca clareza por um ganho minúsculo de desempenho.
Home

Respostas:


207

Sua verdadeira pergunta parece ser:

Por quê:

null >= 0; // true

Mas:

null == 0; // false

O que realmente acontece é que o Operador Maior que ou Igual ( >=) executa coerção de tipo ( ToPrimitive), com um tipo de dica de Number, na verdade todos os operadores relacionais têm esse comportamento.

nullé tratado de maneira especial pelo Operador Equals ( ==). Em resumo, ele apenas obriga a undefined:

null == null; // true
null == undefined; // true

Valor, como false, '', '0', e []são sujeitos a tipo numérico coerção, todos eles coagir a zero.

Você pode ver os detalhes internos desse processo no algoritmo de comparação de igualdade abstrata e no algoritmo de comparação relacional abstrata .

Em suma:

  • Comparação relacional: se os dois valores não forem do tipo String, ToNumberserá chamado nos dois. É o mesmo que adicionar um +na frente, o que, para coações nulas a 0.

  • Comparação de Igualdade: apenas chama ToNumberStrings, Numbers e Booleans.


1
Oi CMS, conforme sua explicação, a primitiva nula é 0, então 0> = 0 retorna true e == está retornando false.mas, de acordo com o algoritmo ecma Se Type (x) for Object e Type (y) for String ou Number, devolver o resultado da ToPrimitive comparação (x) == y.then neste ele deve retornar true.please me explicar
bharath muppa

para mim a resposta não fornece uma resposta - null is treated in a special way by the Equals Operator (==). In a brief, it only coerces to undefined:- e o que? Você pode explicar por que null >= 0? :)
Andrey Deineko

@bharathmuppa @ andrey-deineko: O restante da resposta do CMS está aqui: O algoritmo de comparação relacional abstrata, que explica no ponto 3. que, se os dois valores não forem do tipo String, ToNumber será chamado em ambos. É o mesmo que adicionar um +na frente, o que, para coações nulas a 0. A igualdade chama apenas ToNumber em Strings, Numbers e Booleans.
Michael Liquori

7
Boa descrição, mas não gosto. Em qualquer idioma (x == 0 || x> 0) deve ser equivalente a (x> = 0). javascript é uma linguagem estúpida.
31816 John Henckel

1
É simplesmente um erro na especificação realmente (porque matematicamente é errado), e não há nada a fazer sobre isso há milhões de sites depende de comparações nulos ^^'
mahieddine

14

Gostaria de estender a pergunta para melhorar ainda mais a visibilidade do problema:

null >= 0; //true
null <= 0; //true
null == 0; //false
null > 0;  //false
null < 0;  //false

Isso não faz nenhum sentido. Como as línguas humanas, essas coisas precisam ser aprendidas de cor.


1
Tal como descrito acima, pode ser explicada apenas com uma excepção, como == trata nulo, caso contrário, em todos os casos nula está a ser convertido em 0 usando Número (nulll)
Sourabh Ranka

5

O JavaScript possui comparações rigorosas e de conversão de tipo

null >= 0;é verdade mas (null==0)||(null>0)é falsa

null <= 0;é verdade mas (null==0)||(null<0)é falsa

"" >= 0 também é verdade

Para comparações abstratas relacionais (<=,> =), os operandos são primeiro convertidos em primitivos, depois no mesmo tipo, antes da comparação.

typeof null returns "object"

Quando type é objeto, o javascript tenta especificar o objeto (ou seja, nulo), são executadas as seguintes etapas ( ECMAScript 2015 ):

  1. Se PreferredTypenão foi aprovado, hintseja "padrão".
  2. Senão, se PreferredTypefor hintString, hintseja "string".
  3. Senão PreferredTypeé hintNúmero, hintseja "número".
  4. Let exoticToPrimbe GetMethod(input, @@toPrimitive).
  5. ReturnIfAbrupt(exoticToPrim).
  6. Se exoticToPrimnão for indefinido,
    a) Seja o resultado Call(exoticToPrim, input, «hint»).
    b) ReturnIfAbrupt(result).
    c) Se Type(result)não for Objeto, retorne resultado.
    d) Lance uma exceção TypeError.
  7. Se hintfor "padrão", hintseja "número".
  8. Retorno OrdinaryToPrimitive(input,hint).

Os valores permitidos para a dica são "padrão", "número" e "sequência". Os objetos de data são exclusivos entre o objeto ECMAScript interno, pois tratam "padrão" como sendo equivalente a "sequência". Todos os outros objetos ECMAScript internos tratam "padrão" como sendo equivalente a "número" . ( ECMAScript 20.3.4.45 )

Então, eu acho que se nullconverte em 0.


1

Eu tive o mesmo problema !!. Atualmente, minha única solução é separar.

var a = null;
var b = undefined;

if (a===0||a>0){ } //return false  !work!
if (b===0||b>0){ } //return false  !work!

//but 
if (a>=0){ } //return true !

Pode ser mais clara para fazer em vez disso: if (a!=null && a>=0). Isso esclarece o motivo de não fazer isso >=sozinho: "a pode ser nulo (ou indefinido, que também é '== nulo')".
Home

0
console.log( null > 0 );  // (1) false
console.log( null == 0 ); // (2) false
console.log( null >= 0 ); // (3) true

Matematicamente, isso é estranho. O último resultado afirma que "nulo é maior ou igual a zero", portanto, em uma das comparações acima, deve ser verdadeira, mas ambas são falsas.

O motivo é que uma verificação ==e comparações de igualdade > < >= <=funcionam de maneira diferente. As comparações convertem nulo em um número, tratando-o como 0. É por isso que (3) null >= 0é truee (1) null > 0é false.

Por outro lado, a verificação de igualdade ==para undefinede nullé definida de tal forma que, sem qualquer conversão, eles igual uns dos outros e não fazer qualquer outra igual nada. É por isso que (2) null == 0é false.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.