Por que isNaN (“”) (string com espaços) é igual a false?

160

Em JavaScript, por que isNaN(" ")avaliar para false, mas isNaN(" x")avaliar para true?

Estou realizando operações numéricas em um campo de entrada de texto, e eu estou verificando se o campo for null, ""ou NaN. Quando alguém digita um punhado de espaços no campo, minha validação falha nos três, e estou confuso sobre o porquê de passar pela isNaNverificação.

IVR Avenger
fonte
1
Hm ... não tenho certeza para onde foi a outra metade do assunto. Ele deveria ler: "JavaScript: Por que o isNaN (" ") é avaliado como falso?"
IVR Avenger
Sim, esse é o comportamento (vazio ou espaço retorna falso para isNaN), mas não encontrei as especificações exatas dessa função.
Lucero
Aqui está uma pergunta que responde a esta: http://stackoverflow.com/questions/115548/why-is-isnannull-false-in-js
Lucero
Javascript nessas questões parece vodu! Você nunca sabe e a explicação é sempre bastante complexa. "" == false // trueeisNaN(" ") // false
João Pimentel Ferreira

Respostas:

155

JavaScript interpreta uma cadeia vazia como um 0, que falha no teste isNAN. Você pode usar parseInt na string primeiro, que não converterá a string vazia em 0. O resultado deve falhar é NAN.

Antonio Haley
fonte
53
Mas parseInt ("123abcd") retorna 123, o que significa que isNaN (parseInt ("123abcd")) retornará false enquanto deve retornar true!
Pawan Nogariya
11
Assim como sobre (IsNaN (string) || isNaN (parseInt (string)))
Matt
5
Existem 2 etapas na interpretação isNaN(arg). 1) Converta arg em número, 2) Verifique se esse número é o valor numérico NaN. Isso me ajudou a entender melhor.
Xdhmoore
3
@Antonio_Haley Espere um minuto, eu não entendo. Se "JavaScript interpreta uma sequência vazia como 0", por que parseInt ("") retorna NaN?
Jean-François Beauchamp
1
@ Jean-François Você está certo, a afirmação mais correta seria "isNaN interpreta uma string vazia como 0", não o próprio JavaScript.
Antonio Haley
82

Você pode achar isso surpreendente ou talvez não, mas aqui está um código de teste para mostrar a loucura do mecanismo JavaScript.

document.write(isNaN("")) // false
document.write(isNaN(" "))  // false
document.write(isNaN(0))  // false
document.write(isNaN(null)) // false
document.write(isNaN(false))  // false
document.write("" == false)  // true
document.write("" == 0)  // true
document.write(" " == 0)  // true
document.write(" " == false)  // true
document.write(0 == false) // true
document.write(" " == "") // false

então isso significa que

" " == 0 == false

e

"" == 0 == false

mas

"" != " "

Diverta-se :)

Nick Berardi
fonte
5
+1 Ótima postagem. Você pode adicionar como o operador triplo igual (=== e! ==) se encaixa aqui?
bendewey
2
Você deve tentar NaN === NaN ou NaN == NaN ;-) Não sei se tudo isso significa que o mecanismo javascript é maluco ou se o javascript é ruim para programadores malucos.
KooiInc 5/05
10
@Kooilnc o fato de que NaN! = NaN é, na verdade, uma boa escolha pela primeira vez. A idéia é que o NaN é quase sempre o resultado de um cálculo diferente do que o programador pretendia, e assumir que os resultados de dois cálculos "errados" são iguais é bastante perigoso, eu diria.
Skrebbel #
2
@Kooilnc para não tirar nem um pouco da loucura do javascript, mas esses NaNs estão apenas obedecendo ao padrão de ponto flutuante IEEE 754. Você pode ler tudo sobre ele, como de costume na grande W: en.wikipedia.org/wiki/NaN
Spike0xff
@NickBerardi F'ing LOL! Estou tão feliz que vi este post. Me ajudou a descobrir por que a função isNaN é tão retardada. Vou retirá-lo do meu código não totalmente desenvolvido no momento e provavelmente nunca o usará novamente. I irá validar para null, ""e " "eu mesmo. Obrigado!
precisa saber é o seguinte
16

Para entender melhor, abra o pdf de especificação do Ecma-Script na página 43 "ToNumber aplicado ao tipo de string"

se uma string tiver uma sintaxe numérica, que pode conter qualquer número de caracteres de espaço em branco, poderá ser convertida para o tipo Number. A cadeia vazia é avaliada como 0. Além disso, a cadeia 'Infinito' deve fornecer

isNaN('Infinity'); // false
Rafael
fonte
13

Tente usar:

alert(isNaN(parseInt("   ")));

Ou

alert(isNaN(parseFloat("    ")));
Bendewey
fonte
3
oi senhor, isNaN (parseInt ( "123a")): retornará 123 de modo solução ur não vai funcionar, se a cadeia contém aplha numérico
Sajjad Ali Khan
6

Do MDNmotivo do problema que você está enfrentando

Quando o argumento para a função isNaN não é do tipo Number, o valor é coagido primeiro a um Number. O valor resultante é então testado para determinar se é NaN.

Convém verificar a resposta abrangente a seguir, que também cobre a comparação de NaN para igualdade.

Como testar se uma variável JavaScript é NaN

dopeddude
fonte
5

Eu acho que é por causa da digitação do Javascript: ' 'é convertido em zero, enquanto que 'x'não é:

alert(' ' * 1); // 0
alert('x' * 1); // NaN
Greg
fonte
4

Se você deseja implementar uma função isNumber precisa, aqui está uma maneira de fazê-lo a partir do Javascript: The Good Parts, por Douglas Crockford [página 105]

var isNumber = function isNumber(value) {
   return typeof value === 'number' && 
   isFinite(value);
}
Brian Grinstead
fonte
4
@Xyan caso em que esta função não é muito útil para realizar a tarefa do OP estava pedindo para fazer, que era para inspecionar a representação de um número ...
ErikE
usando o chamado operador de igualdade estrita de qualquer valor dado contra um string literal, como "número" é estúpido,
Bekim Bacaj
4

A resposta não totalmente correta

A resposta altamente votada e aceita de Antonio Haley aqui pressupõe que esse processo passa pela parseIntfunção do JavaScript :

Você pode usar parseInt na cadeia de caracteres ... O resultado deve falhar é isNAN.

Podemos facilmente refutar essa declaração com a string "123abc":

parseInt("123abc")    // 123     (a number...
isNaN("123abc")       // true     ...which is not a number)

Com isso, podemos ver que a parseIntfunção do JavaScript retorna "123abc"como o número 123, mas sua isNaNfunção nos diz que "123abc" não é um número.

A resposta correta

O ECMAScript-262 define como a isNaNverificação funciona na seção 18.2.3 .

18.2.3 isNaN(Número)

A isNaNfunção é o %isNaN%objeto intrínseco. Quando a isNaNfunção é chamada com um número de argumento, são executadas as seguintes etapas:

  1. Let numbe? ToNumber(number).
  2. Se numestiver NaN, retorne true.
  3. Caso contrário, retorne false.

A ToNumberfunção a que se refere também é definida na seção 7.1.3 do ECMAScript-262 . Aqui, somos informados como o JavaScript lida com Strings que são passadas para esta função.

O primeiro exemplo dado na pergunta é uma sequência que contém nada além de caracteres de espaço em branco. Esta seção afirma que:

Um StringNumericLiteralque está vazio ou contém apenas espaço em branco é convertido em +0.

A " "sequência de exemplo é, portanto, convertida em +0, que é um número.

A mesma seção também afirma:

Se a gramática não puder interpretar o Stringcomo uma expansão de StringNumericLiteral, o resultado de ToNumberé NaN.

Sem citar todas as verificações contidas nessa seção, o " x"exemplo dado na pergunta cai na condição acima, pois não pode ser interpretado como a StringNumericLiteral. " x"é, portanto, convertido para NaN.

James Donnelly
fonte
2

Não sei por que , mas para contornar o problema, você sempre pode aparar o espaço em branco antes de verificar. Você provavelmente quer fazer isso de qualquer maneira.

Joel Coehoorn
fonte
4
uma sequência vazia aparada também falha no teste isNaN.
Egemenk
2

A função isNaN("")executa uma coerção do tipo String para Number

O ECMAScript 3-5 define os seguintes valores de retorno para o operador typeof:

  • Indefinido
  • objeto (nulo, objetos, matrizes)
  • boleano
  • número
  • corda
  • função

Melhor agrupar nosso teste em um corpo de função:

function isNumber (s) {
    return typeof s == 'number'? true
           : typeof s == 'string'? (s.trim() === ''? false : !isNaN(s))
           : (typeof s).match(/object|function/)? false
           : !isNaN(s)
}

Esta função não tem a intenção de testar o tipo de variável ; em vez disso, testa o valor coagido . Por exemplo, booleanos e strings são coagidos a números, então talvez você queira chamar essa função comoisNumberCoerced()

se não for necessário testar outros tipos além de sequência e número , o seguinte snippet pode ser usado como parte de alguma condição:

if (!isNaN(s) && s.toString().trim()!='') // 's' can be boolean, number or string
    alert("s is a number")
Steven Pribilinskiy
fonte
1

Eu sugiro que você use a seguinte função se você realmente deseja uma verificação adequada se é um número inteiro:

function isInteger(s)
{
   return Math.ceil(s) == Math.floor(s);
}
Bat_Programmer
fonte
1

Isso isNaN(" ")é falso faz parte do comportamento confuso da isNaNfunção global devido à sua coerção de não números a um tipo numérico.

Do MDN :

Desde as versões mais antigas da isNaNespecificação de função, seu comportamento para argumentos não numéricos tem sido confuso. Quando o argumento para a isNaNfunção não é do tipo Número, o valor é coagido primeiro a um Número. O valor resultante é então testado para determinar se é NaN. Portanto, para não-números que, quando coagidos ao tipo numérico, resultam em um valor numérico não-NaN válido (principalmente a cadeia vazia e as primitivas booleanas, que quando coagidas dão valores numéricos zero ou um), o valor retornado "falso" pode ser inesperado; a cadeia vazia, por exemplo, certamente não é um número.

Observe também que, com o ECMAScript 6, também existe agora o Number.isNaNmétodo, que de acordo com o MDN:

Em comparação com a isNaN()função global , Number.isNaN()não sofre o problema de converter forçosamente o parâmetro em um número. Isso significa que agora é seguro transmitir valores que normalmente seriam convertidos em NaN, mas na verdade não são o mesmo valor que NaN. Isso também significa que apenas os valores do número do tipo, que também são NaN, retornam true.

Infelizmente :

Até o Number.isNaNmétodo ECMAScript 6 tem seus próprios problemas, conforme descrito na postagem do blog - Corrigindo o feio problema de JavaScript e ES6 NaN .

lucono
fonte
1

A isNaNfunção espera um número como argumento; portanto, argumentos de qualquer outro tipo (no seu caso, uma string) serão convertidos em número antes que a lógica real da função seja executada. (Esteja ciente queNaN também é um valor do tipo Número!)

Btw. isso é comum a todos funções internas - se eles esperam um argumento de um determinado tipo, o argumento real será convertido usando as funções de conversão padrão. Existem conversões padrão entre todos os tipos básicos (bool, string, número, objeto, data, nulo, indefinido).

A conversão padrão para Stringpara Numberpode ser chamada explícita com Number(). Então podemos ver que:

  • Number(" ") avalia como 0
  • Number(" x") avalia como NaN

Diante disso, o resultado da isNaN função é completamente lógico!

A verdadeira questão é por que a conversão padrão de String para Número funciona da mesma maneira. A conversão de seqüência de caracteres em número realmente pretende converter seqüências numéricas como "123" ou "17.5e4" para números equivalentes. A conversão ignora primeiro o espaço em branco inicial (portanto, "123" é válido) e, em seguida, tenta analisar os demais como um número. Se não for analisável como um número ("x" não é), o resultado será NaN. Mas existe a regra especial explícita de que uma string vazia ou apenas em branco é convertida em 0. Portanto, isso explica a conversão.

Referência: http://www.ecma-international.org/ecma-262/5.1/#sec-9.3.1

JacquesB
fonte
1

Eu escrevi essa pequena função rápida para ajudar a resolver esse problema.

function isNumber(val) {
     return (val != undefined && val != null && val.toString().length > 0 && val.toString().match(/[^0-9\.\-]/g) == null);
};

Ele simplesmente verifica se há caracteres que não são numéricos (0-9), que não são '-' ou '.' E que não são indefinidos, nulos ou vazios e retorna verdadeiro se não houver correspondências. :)

XtraSimplicity
fonte
Um agradecimento tardio por isso; isso resolveu meu problema muito bem.
Henry
1

Como explicado anteriormente, a isNaNfunção coagirá a sequência vazia em um número antes de validá-la, alterando uma sequência vazia para 0 (que é um número válido). No entanto, descobri que a parseIntfunção retornará NaNao tentar analisar uma string vazia ou uma string com apenas espaços. Como tal, a seguinte combinação parece estar funcionando bem:

if ( isNaN(string) || isNaN(parseInt(string)) ) console.log('Not a number!');

Essa verificação funcionará para números positivos, números negativos e números com um ponto decimal, por isso acredito que abrange todos os casos numéricos comuns.

Nadav
fonte
1

NaN ! == "não é um número"

NaN é um valor do tipo de número

esta é uma definição de isNaN () no ECMAScript

1. Let num be ToNumber(number).
2. ReturnIfAbrupt(num).
3. If num is NaN, return true.
4. Otherwise, return false.

Tente converter qualquer valor para número.

Number(" ") // 0
Number("x") // NaN
Number(null) // 0

Se você deseja determinar se o valor é NaN, tente convertê-lo em um valor numérico primeiro.

bitfishxyz
fonte
0

Essa função parecia funcionar nos meus testes

function isNumber(s) {
    if (s === "" || s === null) {
        return false;
    } else {
        var number = parseInt(s);
        if (number == 'NaN') {
            return false;
        } else {
            return true;
        }
    }
}
bruno negrao
fonte
2
Toda a sua função pode ser escrita:return !(s === "" || s === null || parseInt(s) == 'NaN');
ErikE 4/12
0

A respeito

function isNumberRegex(value) {        
    var pattern = /^[-+]?\d*\.?\d*$/i;
    var match = value.match(pattern);
    return value.length > 0 && match != null;
}
Alexander Schmidt
fonte
0

O JavaScript embutido isNaN função, é - como seria de esperar por padrão - um "tipo de operador dinâmico". Portanto, todos os valores que (durante o processo DTC) podem gerar um valor verdadeiro simples | falso como"", " ", " 000" , não pode ser NaN.

Significando que o argumento fornecido passará primeiro por uma conversão como em:

function isNaNDemo(arg){
   var x = new Number(arg).valueOf();
   return x != x;
}

Explicação:

Na linha superior do corpo da função, estamos (primeiro) tentando converter com êxito o argumento em um objeto numérico. E (segundo), usando o operador de ponto, estamos - para nossa própria conveniência - retirando imediatamente, o valor primitivo do objeto criado.

Na segunda linha, estamos pegando o valor obtido na etapa anterior e a vantagem do fato de NaN não ser igual a nada no universo, nem mesmo a si mesmo, por exemplo:NaN == NaN >> false para finalmente compará-lo (por desigualdade) consigo mesmo .

Dessa forma, o retorno da função produzirá true somente quando, e somente se, o retorno do argumento fornecido, for uma tentativa falha de conversão para um objeto numérico, ou seja, um número não-numérico; por exemplo, NaN.


isNaNstatic ()

No entanto, para um operador de tipo estático - se necessário e quando necessário - podemos escrever uma função muito mais simples, como:

function isNaNstatic(x){   
   return x != x;
}

E evite o DTC completamente para que, se o argumento não for explicitamente um número NaN, ele retornará falso. Portanto, testando contra o seguinte:

isNaNStatic(" x"); // will return false porque ainda é uma corda.

No entanto: isNaNStatic(1/"x"); // will of course return true.como será, por exemplo,isNaNStatic(NaN); >> true .

Mas isNaN, ao contrário do , isNaNStatic("NaN"); >> falseporque (o argumento) é uma string comum.

ps: A versão estática do isNaN pode ser muito útil em cenários de codificação modernos. E pode muito bem ser uma das principais razões pelas quais dediquei meu tempo postando isso.

Saudações.

Bekim Bacaj
fonte
0

isNAN(<argument>)é uma função para saber se o argumento fornecido é um número ilegal. isNaNtipifica os argumentos no tipo Number. Se você deseja verificar se o argumento é numérico ou não? Por favor, use a $.isNumeric()função no jQuery.

Ou seja, isNaN (foo) é equivalente a isNaN (Number (foo)). Ele aceita qualquer string com todos os números como números por razões óbvias. Por ex.

isNaN(123) //false
isNaN(-1.23) //false
isNaN(5-2) //false
isNaN(0) //false
isNaN('123') //false
isNaN('Hello') //true
isNaN('2005/12/12') //true
isNaN('') //false
isNaN(true) //false
isNaN(undefined) //true
isNaN('NaN') //true
isNaN(NaN) //true
isNaN(0 / 0) //true
Om Sao
fonte
0

Eu uso isso

    function isNotANumeric(val) {
    	if(val.trim && val.trim() == "") {
         return true;
      } else {
      	 return isNaN(parseFloat(val * 1));
      }
    }
    
    alert(isNotANumeric("100"));  // false
    alert(isNotANumeric("1a"));   // true
    alert(isNotANumeric(""));     // true
    alert(isNotANumeric("   "));  // true

kiranvj
fonte
0

Ao verificar se determinado valor string com espaços em branco ou " "é isNaNtalvez tentar executar a validação de corda, exemplo:

// value = "123 " if (value.match(/\s/) || isNaN(value)) { // do something }

Channox
fonte