Pergunta

Eu tenho uma pergunta rápida (espero!). Em JS, por que isNaN(" ") avaliar como falso, mas isNaN(" x") avaliar a verdade?

Estou realizando operações numéricas em um campo de entrada de texto, e estou verificando se o campo é nulo, "", ou NaN. Quando alguém digita um punhado de espaços no campo, a minha validação falhar em todos os três, e eu estou confuso sobre o porquê ele fica após o check Isnan.

Obrigado!

Foi útil?

Solução

JavaScript interpreta uma cadeia vazia como 0, que, em seguida, falha no teste Isnan. Você pode usar parseInt na corda primeiro que não irá converter a cadeia vazia a 0. O resultado deve então falhar Isnan.

Outras dicas

Você pode encontrar este surpreendente ou talvez não, mas aqui é um código de teste para mostrar-lhe o wackyness do motor 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

e

"" != " "

Divirta-se:)

Para entender melhor, por favor, abra Ecma-Script especificação pdf na página 43 "tonumber aplicado ao tipo string"

Se uma corda tem uma sintaxe numérica, que pode conter qualquer número de caracteres de espaço em branco, ele pode ser convertido para o tipo Number. string vazia avalia a 0. Também a string 'Infinity' deve dar

isNaN('Infinity'); // false

Tente usar:

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

ou

alert(isNaN(parseFloat("    ")));

A partir MDN razão para o problema que estão enfrentando

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

Você pode querer verificar a seguinte resposta abrangente que cobre a comparação NaN pela igualdade também.

como testar se uma variável JavaScript é NaN

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

alert(' ' * 1); // 0
alert('x' * 1); // NaN

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

var isNumber = function isNumber(value) {
   return typeof value === 'number' && 
   isFinite(value);
}

A resposta não-inteiro-Correct

O Antonio Haley altamente upvoted e aceita resposta aqui faz um pressuposto errado de que este processo passa por função parseInt de JavaScript:

Você pode usar parseInt na corda ... O resultado deve então falhar Isnan.

Podemos facilmente refutar esta afirmação com o "123abc" string:

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

Com isso, podemos ver que a função parseInt retornos de JavaScript "123abc" como o número 123, mas sua função isNaN nos diz que "123abc" não é um número.

A resposta correta

ECMAScript-262 define como os trabalhos de verificação isNaN em seção 18.2.3 .

18.2.3 isNaN (Number)

A função isNaN é o objecto intrínseca %isNaN%. Quando a função isNaN é chamado com um número de argumento, os seguintes passos são tomados:

  1. Let num ser? ToNumber(number).
  2. Se num é NaN, retorno true.
  3. Caso contrário, o retorno false.

A função ToNumber ele faz referência também é definido na seção ECMAScript-262 do 7.1.3 . Em aqui, nós nos disse como JavaScript lida com cordas que são passados ??para esta função.

O primeiro exemplo dado na questão é uma string contendo nada além de caracteres de espaço em branco. Esta seção estabelece que:

Um StringNumericLiteral que é vazio ou contém apenas o espaço em branco é convertido para +0.

O exemplo corda " " é, por conseguinte, convertidos para +0, que é um número.

A mesma seção também afirma:

Se a gramática não pode interpretar o String como uma expansão da StringNumericLiteral, então o resultado de ToNumber é NaN.

Sem citar todas as verificações contidas dentro dessa seção, o exemplo " x" dada na questão cai na condição acima, uma vez que não pode ser interpretado como um StringNumericLiteral. " x" é, portanto, convertido em NaN.

Eu não tenho certeza por , mas para contornar o problema que você poderia sempre espaços em branco guarnição antes de verificar. Você provavelmente quer fazer isso de qualquer maneira.

Os executa função isNaN("") um String para Número tipo de coerção

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

  • indefinido
  • objecto (nulos, objetos, matrizes)
  • boolean
  • número
  • string
  • função

Melhor para embrulhar o nosso teste em um corpo da 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 é intented a variável de teste tipo , em vez disso, testa a valor coagido . Por exemplo, booleans e cordas são coagidos a números, então talvez você pode querer chamar essa função como isNumberCoerced()

Se não há necessidade de teste para tipos que não string e número , em seguida, o seguinte trecho 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")

Eu sugiro que você use a seguinte função se você quiser realmente um bom check se é um inteiro:

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

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

De MDN :

Desde os primeiros versões da especificação da função isNaN, o seu comportamento para os argumentos não numéricos foi confuso. Quando o argumento para a função isNaN não é do tipo de número, o valor é primeiro convertido para um número. O valor resultante é então testado para determinar se é NaN. Assim, para os não-números que quando coagido a resultado tipo numérico em um valor válido non-NaN numérico (nomeadamente a string vazia e primitivos boolean, que quando Coerced dão valores numéricos zero ou um), o valor "false" retornado pode ser inesperado; a cadeia vazia, por exemplo, é certamente "não é um número".

Note-se também que com ECMAScript 6, há também agora o método Number.isNaN, que de acordo com a MDN:

Em comparação com a função isNaN() global, Number.isNaN() não sofre o problema da força converter o parâmetro para um número. Isto significa que é agora seguro para passar valores que normalmente se convertem ao NaN, mas na verdade não são o mesmo valor que NaN. Isto também significa que apenas os valores do número do tipo, que são também NaN, retorno true.

Infelizmente :

Mesmo o método Number.isNaN ECMAScript 6 tem seus próprios problemas, conforme descrito no post - fixação do feio JavaScript e ES6 NaN problema .

Como outro explicada a função isNaN vai obrigar a cadeia vazio em um número antes de validar que, alterando, assim, uma cadeia vazia em 0 (que é um número válido). No entanto, descobri que a função parseInt voltará NaN ao 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!');

Esta verificação irá trabalhar para números positivos, os números negativos e números com um ponto decimal, então eu acredito que abrange todos os casos numéricos comuns.

Esta função parecia estar a trabalhar em meus testes

function isNumber(s) {
    if (s === "" || s === null) {
        return false;
    } else {
        var number = parseInt(s);
        if (number == 'NaN') {
            return false;
        } else {
            return true;
        }
    }
}

E

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

A função isNaN espera um número como argumento, então argumentos de qualquer outro tipo (no seu caso uma string) será convertido em número antes a lógica verdadeira função é executada. (Esteja ciente de que NaN é também um valor do tipo Número!)

Btw. Isso é comum para todas built-in funções - se eles esperam um argumento de um certo tipo, o argumento real serão convertidos utilizando as funções de conversão padrão. Há conversões padrão entre todos os tipos básicos (bool, corda, número, objeto, data, null, indefinido.)

A conversão padrão para String para Number pode ser invocada explícita com Number(). Assim, podemos ver que:

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

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

A verdadeira questão é por isso que a conversão padrão String-a-Number funciona como ele faz. A conversão de cadeia-a-número é realmente a intenção de converter seqüências numéricas como "123" ou "17.5e4" para os números equivalentes. A conversão pula primeiro espaço inicial (de modo "123" é válido) e, em seguida, tenta analisar as pausas como um número. Se não é analisável como um número ( "x" não é), então o resultado é NaN. Mas há a regra especial explícito que uma corda que está vazio ou somente espaços em branco é convertido para 0. Então isso explica a conversão.

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

Eu escrevi essa função pouco rápido para ajudar a resolver este problema.

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

Ele simplesmente verifica a existência de quaisquer caracteres que não são numérico (0-9), que não são '-' '' ou, e que não são indefinido, nulo ou vazio e retorna verdadeiro se não há nenhum resultado. :)

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

O que significa que o argumento fornecido vai primeiro passar por um 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 de número. E (segundo), usando o operador ponto estamos - para nossa própria conveniência -. Imediatamente tirando, primitivo valor do objeto criado

Na segunda linha, estamos tomando o valor obtido na etapa anterior, ea vantagem do fato de que NaN não é igual a qualquer coisa no universo, nem mesmo para si mesmo, por exemplo:. NaN == NaN >> false para finalmente compará-lo (para a desigualdade) com a própria

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


isNaNstatic ()

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

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

E evitar o DTC completamente de modo que se o argumento não é explicitamente um número NaN, ela retornará falso. Portanto, o teste contra o seguinte:

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

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

Mas ao contrário do isNaN, o isNaNStatic("NaN"); >> false porque ele (o argumento) é uma cadeia comum.

P.S .: A versão estática do isNaN pode ser muito útil em cenários de codificação modernas. E pode muito bem ser uma das principais razões que eu levei o meu tempo por este destacamento.

Cumprimentos.

isNAN(<argument>) é uma função para dizer se determinado argumento é o número ilegal. isNaN typecasts os argumentos em tipo de número. Se você quiser verificar se o argumento é numérico ou não? Por favor, use a função $.isNumeric() em jQuery.

Isto é, 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

Eu uso este

    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

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ê quiser determinar se o valor for NaN, você deve tentar convertê-lo para um valor de Number em primeiro lugar.

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

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

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top