在 JavaScript 中,为什么isNaN(" ")
评估为false
,但isNaN(" x")
评估为true
?
我正在对文本输入字段执行数字运算,并且正在检查该字段是null
、""
还是NaN
。当有人在该字段中键入少量空格时,我的三个验证都失败了,我很困惑为什么它会通过isNaN
检查。
在 JavaScript 中,为什么isNaN(" ")
评估为false
,但isNaN(" x")
评估为true
?
我正在对文本输入字段执行数字运算,并且正在检查该字段是null
、""
还是NaN
。当有人在该字段中键入少量空格时,我的三个验证都失败了,我很困惑为什么它会通过isNaN
检查。
JavaScript 将空字符串解释为 0,然后 isNAN 测试失败。您可以首先在字符串上使用 parseInt,它不会将空字符串转换为 0。结果应该会失败 isNAN。
您可能会觉得这很奇怪,也可能不会,但这里有一些测试代码可以向您展示 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
但
"" != " "
玩得开心 :)
为了更好地理解它,请打开第 43 页“ToNumber 应用于字符串类型”的Ecma-Script 规范 pdf
如果字符串具有数字语法,可以包含任意数量的空白字符,则可以将其转换为 Number 类型。空字符串计算为 0。字符串 'Infinity' 也应该给出
isNaN('Infinity'); // false
尝试使用:
alert(isNaN(parseInt(" ")));
或者
alert(isNaN(parseFloat(" ")));
从MDN
您面临的问题的原因
当 isNaN 函数的参数不是 Number 类型时,该值首先被强制转换为 Number。然后测试结果值以确定它是否为 NaN。
您可能需要检查以下全面的答案,该答案也涵盖了 NaN 比较的相等性。
我认为这是因为 Javascript 的输入:' '
被转换为零,而'x'
不是:
alert(' ' * 1); // 0
alert('x' * 1); // NaN
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
使用一个参数号调用函数时,将执行以下步骤:
- 让
num
?ToNumber(number)
.- 如果
num
是NaN
,则返回true
。- 否则,返回
false
。
它引用的ToNumber
函数也在ECMAScript-262 的第 7.1.3 节中定义。在这里,我们被告知 JavaScript 如何处理传递给该函数的字符串。
问题中给出的第一个示例是一个只包含空格字符的字符串。本节规定:
StringNumericLiteral
为空或仅包含空格的A将转换为+0
.
示例字符串因此" "
被转换为+0
,它是一个数字。
同一部分还指出:
如果语法不能将 解释
String
为 的扩展StringNumericLiteral
,则 的结果ToNumber
是NaN
。
如果不引用该部分中包含的所有检查," x"
则问题中给出的示例属于上述条件,因为它不能解释为StringNumericLiteral
. " x"
因此转换为NaN
。
如果你想实现一个准确的 isNumber 函数,这里有一种从Javascript 中实现的方法:Douglas Crockford 的 The Good Parts [第 105 页]
var isNumber = function isNumber(value) {
return typeof value === 'number' &&
isFinite(value);
}
该函数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()
如果不需要测试除string和number以外的类型,则可以使用以下代码段作为某些条件的一部分:
if (!isNaN(s) && s.toString().trim()!='') // 's' can be boolean, number or string
alert("s is a number")
如果您真的想要正确检查它是否是整数,我建议您使用以下函数:
function isInteger(s)
{
return Math.ceil(s) == Math.floor(s);
}
这isNaN(" ")
是错误的,这是isNaN
全局函数令人困惑的行为的一部分,因为它将非数字强制转换为数字类型。
来自MDN:
自函数规范的最早版本以来
isNaN
,它对非数字参数的行为一直令人困惑。当isNaN
函数的参数不是 Number 类型时,该值首先被强制转换为 Number。然后测试结果值以确定它是否为NaN
. 因此,对于非数字,当强制转换为数字类型时会产生有效的非 NaN 数值(尤其是空字符串和布尔基元,当强制转换为数字值 0 或 1)时,“false”返回值可能是意料之外的;例如,空字符串肯定是“不是数字”。
另请注意,使用 ECMAScript 6,现在也有该Number.isNaN
方法,根据 MDN:
与全局
isNaN()
函数相比,Number.isNaN()
不会遇到强制将参数转换为数字的问题。这意味着现在可以安全地传递通常会转换为NaN
的值,但实际上与NaN
. 这也意味着只有 number 类型的值,也就是NaN
returntrue
。
不幸的是:
甚至 ECMAScript 6Number.isNaN
方法也有其自身的问题,如博客文章 -修复丑陋的 JavaScript 和 ES6 NaN 问题中所述。
该isNaN
函数需要一个数字作为其参数,因此任何其他类型的参数(在您的情况下为字符串)将在执行实际函数逻辑之前转换为数字。(请注意,这NaN
也是 Number 类型的值!)
顺便提一句。这对于所有内置函数都很常见 - 如果它们需要某种类型的参数,则实际参数将使用标准转换函数进行转换。所有基本类型(bool、string、number、object、date、null、undefined)之间都有标准转换。
可以使用 显式调用String
to的标准转换。所以我们可以看到:Number
Number()
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
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 值。
我不知道为什么,但为了解决这个问题,你总是可以在检查之前修剪空白。无论如何,您可能都想这样做。
我写了这个快速的小函数来帮助解决这个问题。
function isNumber(val) {
return (val != undefined && val != null && val.toString().length > 0 && val.toString().match(/[^0-9\.\-]/g) == null);
};
它只检查任何非数字 (0-9)、非“-”或“.”、非未定义、null 或空字符,如果没有匹配则返回 true。:)
正如其他解释的那样,该isNaN
函数将在验证之前将空字符串强制转换为数字,从而将空字符串更改为 0(这是一个有效数字)。但是,我发现在尝试解析空字符串或只有空格的字符串时,该parseInt
函数会返回。NaN
因此,以下组合似乎运作良好:
if ( isNaN(string) || isNaN(parseInt(string)) ) console.log('Not a number!');
此检查适用于正数、负数和带小数点的数字,因此我相信它涵盖了所有常见的数字情况。
这个功能似乎在我的测试中有效
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;
}
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
。
但与 相反isNaN
,isNaNStatic("NaN"); >> false
因为它(参数)是一个普通字符串。
ps:isNaN 的静态版本在现代编码场景中非常有用。这很可能是我花时间发布此内容的主要原因之一。
问候。
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
我用这个
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
当检查某个字符串值是否带有空格或者" "
可能isNaN
尝试执行字符串验证时,例如:
// value = "123 "
if (value.match(/\s/) || isNaN(value)) {
// do something
}
我发现有一个特定于 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);