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


160

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

我在一个文本输入字段进行数字运算,和我正在检查该字段为null""NaN。当有人在该字段中输入少量空格时,我的所有三个验证都失败了,我困惑为什么它无法通过isNaN检查。


1
嗯...不太确定主题的另一半去了哪里。应该读为“ JavaScript:为什么isNaN(“”)的计算结果为false?
IVR Avenger,2009年

抱歉,这就是行为(对于isNaN,空或空格返回false),但是我没有找到此函数的确切规格。
卢塞罗

这是一个回答这个问题的问题:http
//stackoverflow.com/questions/115548/why-is-isnannull-false-in-js

这些问题上的Javascript好像是巫毒教!您永远不会知道,并且解释总是很复杂。"" == false // trueisNaN(" ") // false
若昂·皮门特尔·费雷拉

Answers:


155

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


53
但是parseInt(“ 123abcd”)返回123,这意味着isNaN(parseInt(“ 123abcd”))将返回false,而应该返回true!
Pawan Nogariya

11
那么(IsNaN(string)|| isNaN(parseInt(string)))
哑光

5
口译有两个步骤isNaN(arg)。1)将arg转换为数字,2)检查该数字是否为数值NaN。这有助于我更好地理解它。
xdhmoore

3
@Antonio_Haley请稍等,我不明白。如果“ JavaScript将空字符串解释为0”,为什么parseInt(“”)返回NaN?
让·弗朗索瓦·比彻姆

1
@Jean-François没错,更正确的说法是“ isNaN将空字符串解释为0”,而不是JavaScript本身。
Antonio Haley 2015年

82

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

"" != " "

玩得开心 :)


5
+1好帖子。您可以在这里添加三等式(===和!==)运算符的方式吗?
bentewey

2
您应该尝试使用NaN === NaN或NaN == NaN ;-)我不知道这是否意味着javascript引擎很古怪,或者说javascript对古怪的程序员不利。
KooiInc,2009年

10
@Kooilnc NaN!= NaN实际上是一次不错的选择。我的想法是,NaN几乎始终是计算结果与程序员意图不同的结果,并且假设两次“错误”的计算结果相等是很危险的。
Skrebbel

2
@Kooilnc不会完全摆脱javascript的麻烦,但是这些NaN只是遵循IEEE 754浮点标准。您可以像往常一样在大型W上阅读有关此内容的所有信息:en.wikipedia.org/wiki/NaN
Spike0xff 2012年

@NickBerardi F'ing哈哈!我很高兴看到这篇文章。帮助我弄清楚了为什么isNaN功能如此受阻。我现在将其从我尚未完全开发的代码中删除,并且可能永远不会再使用它。我将验证了null""" "我自己。谢谢!
VoidKing

16

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

如果字符串具有数字语法,可以包含任意数量的空格字符,则可以将其转换为Number类型。空字符串的求值为0。字符串“ Infinity”也应为

isNaN('Infinity'); // false

13

尝试使用:

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

要么

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

3
嗨,先生,isNaN(parseInt(“ 123a”)):将返回123,因此如果字符串包含aplha数字,则您的解决方案将不起作用
Sajjad Ali Khan


5

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

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

4

如果您想实现一个准确的isNumber函数,可以使用Javascript的一种方法 Douglas Crockford 撰写的The Good Parts [第105页]

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

4
@Xyan在这种情况下,此功能对执行OP要求执行的任务不是很有帮助,该任务是检查数字的字符串表示形式
ErikE 2012年

对字符串文字(例如“ number”)使用任何给定值的所谓严格相等运算符都是愚蠢的,
Bekim Bacaj

4

不完全正确的答案

Antonio Haley 对此高度评价和接受的答案做出了错误的假设,认为该过程是通过JavaScript parseInt函数进行的:

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

我们可以使用字符串轻松反驳此声明"123abc"

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

这样,我们可以看到JavaScript的parseInt函数返回"123abc"为number 123,但是其isNaN函数告诉我们这"123abc" 不是数字。

正确答案

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

18.2.3 isNaN(数量)

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

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

ECMAScript-262的7.1.3节中ToNumber也定义了它引用的功能。在这里,我们了解了JavaScript如何处理传递给此函数的字符串。

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

StringNumericLiteral那是空的或仅包含空白转换成+0

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

同一部分还指出:

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

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


2

我不确定为什么,但是要解决该问题,您可以始终在检查之前修剪空白。无论如何,您可能都想这样做。


4
修剪后的空字符串也无法通过isNaN测试。
Egemenk

2

该函数isNaN("")执行从String到Number 类型的强制转换

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

1

如果您确实希望正确检查它是否为整数,建议您使用以下函数:

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

1

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

MDN

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

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

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

不幸的是

Number.isNaN正如博客文章- 修复难看的JavaScript和ES6 NaN问题中概述的那样,甚至ECMAScript 6 方法也有其自身的问题


1

isNaN函数期望使用Number作为其参数,因此执行实际的函数逻辑之前,任何其他类型的参数(在您的情况下为字符串)都将转换为Number 。(意识到NaN也是Number类型的值!)

顺便说一句。这是所有人的共同点内置函数 -如果它们期望某个类型的参数,则将使用标准转换函数来转换实际参数。所有基本类型(布尔型,字符串,数字,对象,日期,空,未定义)之间都有标准转换。

可以使用显式调用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


1

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

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

它只是检查所有不是数字(0-9),不是'-'或'。',不是undefined,null或empty的字符,如果没有匹配项,则返回true。:)


迟到了,谢谢你。这很好地解决了我的问题。
亨利

1

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

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

此检查将适用于正数,负数和带小数点的数字,因此我认为它可以涵盖所有常见的数值情况。


1

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,则应首先尝试将其转换为数字值。


0

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

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

2
您的整个函数可以写成:return !(s === "" || s === null || parseInt(s) == 'NaN');
ErikE 2012年


0

JavaScript的内置isNaN功能,是-因为默认情况下应预期- “动态型算”。因此,所有的值(在DTC过程中)都可以产生一个简单的true |。的错误,例如"", " ", " 000",不能为NaN。

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

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

说明:

在函数主体的顶行,我们(首先)试图将自变量成功转换为数字对象。(第二个)使用点运算符-为了我们自己的方便-我们立即剥离所创建对象原始

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

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


isNaNstatic()

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

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的静态版本在现代编码方案中非常有用。这很可能是我花时间张贴此文章的主要原因之一。

问候。


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

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


0

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

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.