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 ):
PreferredType
não foi passado, deixe que a hint
seja "default". PreferredType
for hint
String, deixe a hint
ser "string". PreferredType
é o número da hint
, deixe a hint
ser "número". exoticToPrim
ser GetMethod(input, @@toPrimitive)
. ReturnIfAbrupt(exoticToPrim)
. exoticToPrim
não é indefinido, então Call(exoticToPrim, input, «hint»)
. ReturnIfAbrupt(result)
. Type(result)
não for Object, retorne o resultado. hint
for "padrão", deixe que a hint
seja "número". 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 !