179

在 JavaScript 中,为什么isNaN(" ")评估为false,但isNaN(" x")评估为true

我正在对文本输入字段执行数字运算,并且正在检查该字段是null""还是NaN。当有人在该字段中键入少量空格时,我的三个验证都失败了,我很困惑为什么它会通过isNaN检查。

4

25 回答 25

170

JavaScript 将空字符串解释为 0,然后 isNAN 测试失败。您可以首先在字符串上使用 parseInt,它不会将空字符串转换为 0。结果应该会失败 isNAN。

于 2009-05-05T15:27:11.207 回答
85

您可能会觉得这很奇怪,也可能不会,但这里有一些测试代码可以向您展示 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

所以这意味着

" " == 0 == false

"" == 0 == false

"" != " "

玩得开心 :)

于 2009-05-05T15:34:54.527 回答
18

为了更好地理解它,请打开第 43 页“ToNumber 应用于字符串类型”的Ecma-Script 规范 pdf

如果字符串具有数字语法,可以包含任意数量的空白字符,则可以将其转换为 Number 类型。空字符串计算为 0。字符串 'Infinity' 也应该给出

isNaN('Infinity'); // false
于 2009-05-05T15:32:00.837 回答
12

尝试使用:

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

或者

alert(isNaN(parseFloat("    ")));
于 2009-05-05T15:27:27.383 回答
7

MDN您面临的问题的原因

当 isNaN 函数的参数不是 Number 类型时,该值首先被强制转换为 Number。然后测试结果值以确定它是否为 NaN。

您可能需要检查以下全面的答案,该答案也涵盖了 NaN 比较的相等性。

如何测试 JavaScript 变量是否为NaN

于 2015-05-03T07:25:39.173 回答
6

我认为这是因为 Javascript 的输入:' '被转换为零,而'x'不是:

alert(' ' * 1); // 0
alert('x' * 1); // NaN
于 2009-05-05T15:27:37.523 回答
6

不完全正确的答案

Antonio Haley 的高度赞成和接受的答案在这里错误地假设这个过程通过 JavaScript 的parseInt函数:

您可以在字符串上使用 parseInt ...然后结果应该失败 isNAN。

我们可以很容易地用字符串反驳这个说法"123abc"

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

有了这个,我们可以看到 JavaScript 的parseInt函数"123abc"以数字的形式返回123,但它的isNaN函数告诉我们这"123abc" 不是数字。

正确答案

ECMAScript-262 在第 18.2.3 节中定义了isNaN检查的工作方式。

18.2.3 isNaN(数量)

isNaN函数是%isNaN%内在对象。当isNaN使用一个参数号调用函数时,将执行以下步骤:

  1. numToNumber(number).
  2. 如果numNaN,则返回true
  3. 否则,返回false

它引用的ToNumber函数也在ECMAScript-262 的第 7.1.3 节中定义。在这里,我们被告知 JavaScript 如何处理传递给该函数的字符串。

问题中给出的第一个示例是一个只包含空格字符的字符串。本节规定:

StringNumericLiteral为空或仅包含空格的A将转换为+0.

示例字符串因此" "被转换为+0,它是一个数字。

同一部分还指出:

如果语法不能将 解释String为 的扩展StringNumericLiteral,则 的结果ToNumberNaN

如果不引用该部分中包含的所有检查," x"则问题中给出的示例属于上述条件,因为它不能解释为StringNumericLiteral. " x"因此转换为NaN

于 2016-03-10T12:11:38.117 回答
4

如果你想实现一个准确的 isNumber 函数,这里有一种从Javascript 中实现的方法:Douglas Crockford 的 The Good Parts [第 105 页]

var isNumber = function isNumber(value) {
   return typeof value === 'number' && 
   isFinite(value);
}
于 2009-05-05T15:38:23.287 回答
3

该函数isNaN("")执行字符串到数字类型强制

ECMAScript 3-5 为 typeof 运算符定义了以下返回值:

  • 不明确的
  • 对象(空,对象,数组)
  • 布尔值
  • 数字
  • 细绳
  • 功能

最好将我们的测试包装在一个函数体中:

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

此函数不打算测试变量类型,而是测试强制值。例如,布尔值和字符串被强制转换为数字,因此您可能希望将此函数称为isNumberCoerced()

如果不需要测试除stringnumber以外的类型,则可以使用以下代码段作为某些条件的一部分:

if (!isNaN(s) && s.toString().trim()!='') // 's' can be boolean, number or string
    alert("s is a number")
于 2013-09-13T21:38:09.747 回答
2

如果您真的想要正确检查它是否是整数,我建议您使用以下函数:

function isInteger(s)
{
   return Math.ceil(s) == Math.floor(s);
}
于 2010-10-26T09:39:40.603 回答
2

isNaN(" ")是错误的,这是isNaN全局函数令人困惑的行为的一部分,因为它将非数字强制转换为数字类型。

来自MDN

自函数规范的最早版本以来isNaN,它对非数字参数的行为一直令人困惑。当isNaN函数的参数不是 Number 类型时,该值首先被强制转换为 Number。然后测试结果值以确定它是否为NaN. 因此,对于非数字,当强制转换为数字类型时会产生有效的非 NaN 数值(尤其是空字符串和布尔基元,当强制转换为数字值 0 或 1)时,“false”返回值可能是意料之外的;例如,空字符串肯定是“不是数字”。

另请注意,使用 ECMAScript 6,现在也有该Number.isNaN方法,根据 MDN:

与全局isNaN()函数相比,Number.isNaN()不会遇到强制将参数转换为数字的问题。这意味着现在可以安全地传递通常会转换为NaN的值,但实际上与NaN. 这也意味着只有 number 类型的值,也就是NaNreturn true

不幸的是

甚至 ECMAScript 6Number.isNaN方法也有其自身的问题,如博客文章 -修复丑陋的 JavaScript 和 ES6 NaN 问题中所述。

于 2015-04-29T15:22:11.520 回答
2

isNaN函数需要一个数字作为其参数,因此任何其他类型的参数(在您的情况下为字符串)将在执行实际函数逻辑之前转换为数字。(请注意,这NaN也是 Number 类型的值!)

顺便提一句。这对于所有内置函数都很常见 - 如果它们需要某种类型的参数,则实际参数将使用标准转换函数进行转换。所有基本类型(bool、string、number、object、date、null、undefined)之间都有标准转换。

可以使用 显式调用Stringto的标准转换。所以我们可以看到:NumberNumber()

  • Number(" ")评估为0
  • Number(" x")评估为NaN

鉴于此,isNaN函数的结果是完全合乎逻辑的!

真正的问题是为什么标准的字符串到数字的转换会像它那样工作。字符串到数字的转换实际上是为了将像“123”或“17.5e4”这样的数字字符串转换为等效的数字。转换首先跳过初始空白(因此“123”有效),然后尝试将其余部分解析为数字。如果它不能解析为数字(“x”不是),则结果为 NaN。但是有一个明确的特殊规则,即空字符串或只有空格的字符串将转换为 0。所以这解释了转换。

参考: http: //www.ecma-international.org/ecma-262/5.1/#sec-9.3.1

于 2015-07-23T09:25:40.823 回答
2

NaN!== "不是数字"

NaN是数字类型的值

这是 ECMAScript 中 isNaN() 的定义

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

尝试将任何值转换为数字。

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

如果要确定该值是否为NaN,则应先尝试将其转换为 Number 值。

于 2018-08-08T10:03:56.800 回答
1

我不知道为什么,但为了解决这个问题,你总是可以在检查之前修剪空白。无论如何,您可能都想这样做。

于 2009-05-05T15:28:00.830 回答
1

我写了这个快速的小函数来帮助解决这个问题。

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

它只检查任何非数字 (0-9)、非“-”或“.”、非未定义、null 或空字符,如果没有匹配则返回 true。:)

于 2015-12-14T00:18:08.487 回答
1

正如其他解释的那样,该isNaN函数将在验证之前将空字符串强制转换为数字,从而将空字符串更改为 0(这是一个有效数字)。但是,我发现在尝试解析空字符串或只有空格的字符串时,该parseInt函数会返回。NaN因此,以下组合似乎运作良好:

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

此检查适用于正数、负数和带小数点的数字,因此我相信它涵盖了所有常见的数字情况。

于 2017-08-28T03:15:11.183 回答
0

这个功能似乎在我的测试中有效

function isNumber(s) {
    if (s === "" || s === null) {
        return false;
    } else {
        var number = parseInt(s);
        if (number == 'NaN') {
            return false;
        } else {
            return true;
        }
    }
}
于 2012-02-03T12:41:26.030 回答
0

关于什么

function isNumberRegex(value) {        
    var pattern = /^[-+]?\d*\.?\d*$/i;
    var match = value.match(pattern);
    return value.length > 0 && match != null;
}
于 2013-07-12T13:22:57.953 回答
0

JavaScript内置的isNaN函数是 - 正如默认情况下所预期的那样 - 一个“动态类型运算符”。因此(在 DTC 过程中)可能产生简单真 | 的所有值。假如"", " ", " 000", 不能为 NaN。

这意味着提供的参数将首先进行转换,如下所示:

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

解释:

在函数体的第一行,我们(首先)尝试成功地将参数转换为数字对象。并且(第二),我们使用点运算符——为了我们自己的方便——立即剥离所创建对象原始

在第二行中,我们取上一步中获得的值,以及NaN不等于宇宙中的任何东西,甚至不等于自身这一事实的优势,例如:NaN == NaN >> false最终将其(不等式)与自身进行比较.

这样,只有当且仅当提供的参数返回是转换为数字对象(即非数字数字)的失败尝试时,函数才会返回true ;例如,NaN。


isNaN静态()

但是,对于静态类型运算符 - 如果需要和需要时 - 我们可以编写一个更简单的函数,例如:

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

并完全避免 DTC,这样如果参数不是明确的 NaN 数,它将返回 false。因此,针对以下内容进行测试:

isNaNStatic(" x"); // will return false因为它仍然是一个字符串。

但是: isNaNStatic(1/"x"); // will of course return true.例如将isNaNStatic(NaN); >> true

但与 相反isNaNisNaNStatic("NaN"); >> false因为它(参数)是一个普通字符串。

ps:isNaN 的静态版本在现代编码场景中非常有用。这很可能是我花时间发布此内容的主要原因之一。

问候。

于 2017-01-08T01:01:53.293 回答
0

isNAN(<argument>)是一个判断给定参数是否为非法数字的函数。 isNaN将参数类型转换为 Number 类型。如果要检查参数是否为数字?请$.isNumeric()在 jQuery 中使用函数。

也就是说, isNaN(foo) 等价于 isNaN(Number(foo)) 出于显而易见的原因,它接受具有所有数字作为数字的任何字符串。例如。

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
于 2017-04-12T06:32:11.530 回答
0

我用这个

    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

于 2017-10-27T12:41:53.830 回答
0

当检查某个字符串值是否带有空格或者" "可能isNaN尝试执行字符串验证时,例如:

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

于 2018-08-13T07:07:56.410 回答
0

我发现有一个特定于 Number 类的方法很方便(因为像 parseInt 这样进行转换的其他函数对其中一些值有不同的输出)并使用原型继承。

Object.assign(Number.prototype, {
  isNumericallyValid(num) {
    if (
      num === null
      || typeof num === 'boolean'
      || num === ''
      || Number.isNaN(Number(num))
    ) {
      return false;
    }
    return true;
  }
});
于 2020-09-01T02:20:46.747 回答
0

let isNotNumber = val => isNaN(val) || (val.trim && val.trim() === '');

console.log(isNotNumber(' '));
console.log(isNotNumber('1'));
console.log(isNotNumber('123x'));
console.log(isNotNumber('x123'));
console.log(isNotNumber('0'));
console.log(isNotNumber(3));
console.log(isNotNumber('    x'));
console.log(isNotNumber('1.23'));
console.log(isNotNumber('1.23.1.3'));

if(!isNotNumber(3)){
  console.log('This is a number');
}

于 2021-07-13T12:53:15.487 回答
0

我使用以下。

x=(isNaN(parseFloat(x)))? 0.00 : parseFloat(x);

于 2021-08-26T11:43:46.873 回答