NaN
NaN 全局属性表示“非数字”(Not-A-Number)的值。
试一试
function sanitize(x) {
if (isNaN(x)) {
return NaN;
}
return x;
}
console.log(sanitize("1"));
// Expected output: "1"
console.log(sanitize("NotANumber"));
// Expected output: NaN
值
与 Number.NaN 具有相同的数值。
NaN 的属性特性 | |
|---|---|
| 可写 | 否 |
| 可枚举 | 否 |
| 可配置 | 否 |
描述
NaN 是全局对象的属性。换句话说,它是全局作用域中的一个变量。
在现代浏览器中,NaN 是一个不可配置、不可写的属性。即使在不是这种情况时,也要避免覆盖它。
有五种不同类型的操作会返回 NaN:
- 失败的数字转换(例如,显式转换,如
parseInt("blabla")、Number(undefined);或隐式转换,如Math.abs(undefined)) - 结果不是实数的数学运算(例如,
Math.sqrt(-1)) - 不确定形式(例如,
0 * Infinity、1 ** Infinity、Infinity / Infinity、Infinity - Infinity) - 其操作数是或被强制转换为
NaN的方法或表达式(例如,7 ** NaN、7 * "blabla")——这意味着NaN具有传染性 - 其他需要将无效值表示为数字的情况(例如,无效的 Date
new Date("blabla").getTime()、"".charCodeAt(1))
NaN 及其行为并非由 JavaScript 发明。其在浮点算术中的语义(包括 NaN !== NaN)由 IEEE 754 规范。NaN 的行为包括:
- 如果
NaN参与数学运算(但不是位移操作),结果通常也是NaN。(请参阅下面的反例。) - 当
NaN是任何关系比较(>、<、>=、<=)的操作数之一时,结果始终为false。 NaN与任何其他值(包括另一个NaN值)进行比较时,都不相等(通过!=、===和!==)。
NaN 也是 JavaScript 中的假值之一。
示例
测试 NaN
要判断一个值是否为 NaN,请使用 Number.isNaN() 或 isNaN() 以最清晰地确定一个值是否为 NaN——或者,由于 NaN 是唯一一个与自身不相等的值,你可以执行诸如 x !== x 的自比较。
NaN === NaN; // false
Number.NaN === NaN; // false
isNaN(NaN); // true
isNaN(Number.NaN); // true
Number.isNaN(NaN); // true
function valueIsNaN(v) {
return v !== v;
}
valueIsNaN(1); // false
valueIsNaN(NaN); // true
valueIsNaN(Number.NaN); // true
但是,请注意 isNaN() 和 Number.isNaN() 之间的区别:前者在值当前是 NaN,或者在被强制转换为数字后将是 NaN 时返回 true,而后者仅在值当前是 NaN 时才返回 true。
isNaN("hello world"); // true
Number.isNaN("hello world"); // false
出于同样的原因,使用 BigInt 值会通过 isNaN() 抛出错误,但不会通过 Number.isNaN() 抛出错误。
isNaN(1n); // TypeError: Conversion from 'BigInt' to 'number' is not allowed.
Number.isNaN(1n); // false
此外,一些数组方法无法找到 NaN,而另一些则可以。具体来说,查找索引的方法(indexOf()、lastIndexOf())无法找到 NaN,而查找值的方法(includes())可以。
const arr = [2, 4, NaN, 12];
arr.indexOf(NaN); // -1
arr.includes(NaN); // true
// Methods accepting a properly defined predicate can always find NaN
arr.findIndex((n) => Number.isNaN(n)); // 2
有关 NaN 及其比较的更多信息,请参阅相等性比较和同一性。
可观察到的不同 NaN 值
可以生成两个具有不同二进制表示但都是 NaN 的浮点数,因为在 IEEE 754 编码中,任何指数为 0x7ff 且非零尾数的浮点数都是 NaN。在 JavaScript 中,你可以使用类型化数组进行位级操作。
const f2b = (x) => new Uint8Array(new Float64Array([x]).buffer);
const b2f = (x) => new Float64Array(x.buffer)[0];
// Get a byte representation of NaN
const n = f2b(NaN);
const m = f2b(NaN);
// Change the sign bit, which doesn't matter for NaN
n[7] += 2 ** 7;
// n[0] += 2**7; for big endian processors
const nan2 = b2f(n);
console.log(nan2); // NaN
console.log(Object.is(nan2, NaN)); // true
console.log(f2b(NaN)); // Uint8Array(8) [0, 0, 0, 0, 0, 0, 248, 127]
console.log(f2b(nan2)); // Uint8Array(8) [0, 0, 0, 0, 0, 0, 248, 255]
// Change the first bit, which is the least significant bit of the mantissa and doesn't matter for NaN
m[0] = 1;
// m[7] = 1; for big endian processors
const nan3 = b2f(m);
console.log(nan3); // NaN
console.log(Object.is(nan3, NaN)); // true
console.log(f2b(NaN)); // Uint8Array(8) [0, 0, 0, 0, 0, 0, 248, 127]
console.log(f2b(nan3)); // Uint8Array(8) [1, 0, 0, 0, 0, 0, 248, 127]
静默逃逸的 NaN
NaN 在数学运算中会传播,因此通常只需在计算结束时测试一次 NaN 即可检测错误情况。NaN 唯一会静默逃逸的情况是使用幂运算且指数为 0 时,它会立即返回 1,而不测试底数的值。
NaN ** 0 === 1; // true
规范
| 规范 |
|---|
| ECMAScript® 2026 语言规范 # sec-value-properties-of-the-global-object-nan |
浏览器兼容性
加载中…