为什么 isNaN (“”)(带空格的字符串)等于 false?

在 JavaScript 中,为什么 isNaN(" ")的计算结果是 false,而 isNaN(" x")的计算结果是 true

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

83319 次浏览

JavaScript 将空字符串解释为0,这将导致 isNAN 测试失败。您可以首先对字符串使用 parseInt,它不会将空字符串转换为0。结果应该是 NAN 失败。

尝试使用:

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

或者

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

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

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

我不确定 为什么,但是为了解决这个问题,你可以在检查之前修剪空格。你可能还是想这么做。

为了更好地理解它,请打开第43页上的 Ecma-脚本规范 pdf“ ToNumber Applied To the String Type”

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

isNaN('Infinity'); // false

您可能会对此感到惊讶,也可能不会,但是这里有一些测试代码可以向您展示 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

但是

"" != " "

玩得开心:)

如果你想实现一个精确的 isNumber 函数,这里有一种方法可以通过道格拉斯·克罗克福特从 Javascript: 好的部分实现

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

我建议你使用下面的函数,如果你真的想要一个适当的检查,如果它是一个整数:

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

这个函数似乎在我的测试中起作用

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

关于什么

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

函数 isNaN("")执行 字符串到 Number < em > 类型强制

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

  • 未定义
  • 对象(null、对象、数组)
  • 布尔型
  • 号码
  • 绳子
  • 功能

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

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()

如果不需要测试除 绳子号码以外的 类别,那么可以使用下面的代码片段作为某些条件的一部分:

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

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

MDN :

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

还要注意,在 ECMAScript 6中,现在还有 Number.isNaN方法,根据 MDN:

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

不幸的是:

即使是 ECMAScript 6 Number.isNaN方法也有它自己的问题,正如在博客文章 修复丑陋的 JavaScript 和 ES6 NaN 问题中所概述的那样。

MDN的原因,你面临的问题

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

您可能希望检查下面的综合答案,其中也包括 NaN 比较的相等性。

如何测试 JavaScript 变量是否为 NaN

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

顺便说一句。这在 所有内置函数中很常见——如果它们期望一个特定类型的参数,那么实际的参数将使用标准的转换函数进行转换。所有基本类型(bool、 string、 number、 object、 date、 null、 unDefinition)之间都有标准的转换

StringNumber的标准转换可以通过 Number()显式调用,所以我们可以看到:

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

考虑到这一点,isNaN函数的结果是完全符合逻辑的!

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

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

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

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

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

不完全正确的答案

Antonio Haley 的 高度赞成和接受的答案在这里做了一个错误的假设,认为这个过程是通过 JavaScript 的 parseInt函数完成的:

您可以对字符串使用 parseInt... ... 然后结果应该是 NAN。

我们可以很容易地用字符串 "123abc"来反驳这个语句:

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

通过这个函数,我们可以看到 JavaScript 的 parseInt函数返回 "123abc"作为数字 123,而它的 isNaN函数告诉我们 "123abc" 不是是一个数字。

正确答案

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

18.2.3 isNaN(编号)

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

  1. num成为? ToNumber(number)
  2. 如果 numNaN,返回 true
  3. 否则,返回 false

它引用的 ToNumber函数也在 ECMAScript-262’s section 7.1.3 ECMAScript-262’s section 7.1.3中定义。在这里,我们了解到 JavaScript 如何处理传递给这个函数的字符串。

问题中给出的第一个例子是一个只包含空白字符的字符串:

如果 StringNumericLiteral为空或只包含空白,则将其转换为 +0

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

同一节还规定:

如果语法不能将 String解释为 StringNumericLiteral的扩展,那么 ToNumber的结果就是 NaN

没有引用该部分中包含的所有检查,问题中给出的 " x"示例符合上述条件,因为它不能被解释为 StringNumericLiteral。因此," x"被转换为 NaN

< em > JavaScript 内置的 是 NaN函数,默认情况下应该是一个“动态类型运算符”。 因此,(在 DTC 过程中)可能产生简单 true | false 的所有值(例如 "", " ", " 000")都不能是 NaN。

这意味着提供的 争论将首先进行 转变,如下所示:

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

说明:

在函数体的顶行,我们(首先)尝试成功地将参数转换为数字对象。然后(第二步) ,使用点运算符-为了我们自己的方便-立即去掉所创建对象的 < strong > 原语

在第二行中,我们取前一步得到的值,以及 < em > NaN 不等于宇宙中任何东西,甚至不等于它自己这一事实的优点,例如: NaN == NaN >> false最终将它(不等式)与它自己进行比较。

这样,函数返回只有在提供的参数-return 尝试转换为数字对象(即非数字数字; 例如 NaN)失败时才会产生 真实


IsNaNstatic ()

但是,对于静态类型运算符(如果需要的话) ,我们可以编写一个简单得多的函数,比如:

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

并且完全避免 DTC,这样如果参数不是显式的 NaN 数字,它将返回 false。因此,针对以下情况进行测试:

因为它仍然是一个字符串。

然而: 例如 isNaNStatic(NaN); >> true

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

附言: IsNaN 的静态版本在现代编码场景中非常有用。这很可能是我花时间发布这篇文章的主要原因之一。

问候。

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

也就是说,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

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

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

这种检查将工作的正数,负数和小数点的数字,所以我相信它涵盖了所有常见的数字情况。

我用这个

    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! = = “不是一个数字”

NaN是数字类型的值

这是 ECMAScript 中 isNaN ()的定义

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

尝试将任何值转换为 Number。

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

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

当检查某个带空格的字符串值或 " "isNaN时,可以尝试执行字符串验证,例如:

//value = “123” 如果(value.match (/s/) | | isNaN (value)){ 做点什么 }

我发现使用一个特定于 Number 类的方法(因为其他执行转换的函数(如 parseInt)对其中一些值有不同的输出)和使用原型继承非常方便。

Object.assign(Number.prototype, {
isNumericallyValid(num) {
if (
num === null
|| typeof num === 'boolean'
|| num === ''
|| Number.isNaN(Number(num))
) {
return false;
}
return true;
}
});

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');
}

我使用以下方法。

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