NaN
Baseline Widely available
This feature is well established and works across many devices and browser versions. It’s been available across browsers since July 2015.
全局属性 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
// 接受正确定义的断言的方法总是能够找到 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];
// 获取 NaN 的字节表示
const n = f2b(NaN);
const m = f2b(NaN);
// 更改符号位,对于 NaN 而言,这个比特位不重要。
n[7] += 2 ** 7;
// n[0] += 2**7; 对于大端处理器
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]
// 更改第一个比特位,即符号位,对于 NaN 而言,这个比特位不重要。
m[0] = 1;
// m[7] = 1; 对于大端处理器
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
规范
Specification |
---|
ECMAScript Language Specification # sec-value-properties-of-the-global-object-nan |
浏览器兼容性
BCD tables only load in the browser