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

Eu tive que escrever uma rotina que incrementa o valor de uma variável por 1 se o seu tipo é number e atribui 0 à variável se não, onde a variável é inicialmente null ou undefined .

A primeira implementação foi v >= 0 ? v += 1 : v = 0 v >= 0 ? v += 1 : v = 0 porque pensei que qualquer coisa, não um número, tornaria uma expressão aritmética falsa, mas estava errada, pois null >= 0 é avaliado como true. Então eu aprendi null se comporta como 0 e as seguintes expressões são todas avaliadas como verdadeiras.

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

Naturalmente, null não é 0. null == 0 é avaliado como falso. Isso faz com que a expressão aparentemente tautológica (v >= 0 && v <= 0) === (v == 0) falsa.

Por que é null como 0, embora na verdade não seja 0?

Sua verdadeira questão parece ser:

Por quê:

 null >= 0; // true 

Mas:

 null == 0; // false 

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

null é tratado de maneira especial pelo operador Equals ( == ). Em um breve, apenas coage a undefined :

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

Valores como false , '' , '0' e [] estão sujeitos a coerção de tipo numérico, todos eles coagindo 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, ToNumber será chamado em ambos. Isto é o mesmo que adicionar um + na frente, o que, para null, coage a 0 .

  • Comparação de Igualdade: chama somente ToNumber em Strings, Numbers e Booleans.

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 linguagens humanas, essas coisas precisam ser aprendidas de cor.

O JavaScript tem comparações de conversão estrita e de tipo

null >= 0; é verdade, mas (null==0)||(null>0) é falso

null <= 0; é verdade, mas (null==0)||(null<0) é falso

"" >= 0 também é verdade

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

typeof null returns "object"

Quando o tipo é object javascript tenta restringir o object (ou seja, nulo) as seguintes etapas são tomadas ( ECMAScript 2015 ):

  1. Se PreferredType não foi passado, deixe que a hint seja "default".
  2. Senão se PreferredType for hint String, deixe a hint ser "string".
  3. Else PreferredType é o número da hint , deixe a hint ser "número".
  4. Deixe o exoticToPrim ser GetMethod(input, @@toPrimitive) .
  5. ReturnIfAbrupt(exoticToPrim) .
  6. Se exoticToPrim não é indefinido, então
    a) Que o resultado seja Call(exoticToPrim, input, «hint») .
    b) ReturnIfAbrupt(result) .
    c) Se Type(result) não for Object, retorne o resultado.
    d) Lança uma exceção TypeError.
  7. Se a hint for "padrão", deixe que a hint seja "número".
  8. Retornar OrdinaryToPrimitive(input,hint) .

Os valores permitidos para a dica são "default", "number" e "string". Os objects Date, são únicos entre os objects ECMAScript internos, pois tratam "default" como sendo equivalente a "string". Todos os outros objects ECMAScript internos tratam "padrão" como sendo equivalente a "número" . ( ECMAScript 20.3.4.45 )

Então, acho que null converte em 0.

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 !