在JavaScript中将NaN转换为0

325

有没有一种方法可以将 NaN 值转换为 0 而不使用 if 语句?例如:

if (isNaN(a)) a = 0;

每次检查我的变量真的很烦人。

11个回答

762
你可以这样做:
a = a || 0

这将把任何“falsy”值转换为0

“falsy”值包括:

  • false
  • null
  • undefined
  • 0
  • "" (空字符串)
  • NaN (非数字)

如果您喜欢,也可以使用此方法:

a = a ? a : 0;

......这将产生与上述相同的效果。


如果意图是检测不止是NaN,那么可以做相同的操作,但首先进行toNumber转换。

a = +a || 0

此处使用一元 + 运算符尝试将 a 转换为数字。这样做的额外好处是将像数值字符串 '123' 这样的内容转换为数字。

唯一令人意外的情况可能是如果有人传入成功被转换为数字的数组:

+['123']  // 123

在这里,我们有一个数组,只包含一个数值字符串元素。它将成功转换为数字。


1
@Bakudan:说得好。我原本以为OP只关心特定的NaN值。这不能测试所有非数字值。虽然我们可以先尝试进行toNumber转换。我会更新的。 - user113716
啊,这是因为标题是“将NaN转换为0”。不管怎样,现在两种方式都覆盖了。 - user113716
2
谢谢,我已经选定并稍作修改了这段代码 a = a*1 || 0。 - Somebody
如果您使用较新版本的JavaScript,则空值合并运算符(??)将不会产生相同的结果。 - Wildhammer
??存在问题...如果它是NaN,例如parseInt('abc') ?? 10 - Aaron Gong
显示剩余2条评论

48

在JavaScript中,使用双波浪线(双按位非)~~ 可以做一些有趣的事情。例如,您可以将其用作 Math.floor 的替代品,甚至是 parseInt("123", 10) 的替代品!它已经在网络上讨论了很多次,所以我不会在这里解释为什么它起作用,但如果您感兴趣: What is the "double tilde" (~~) operator in JavaScript?

我们可以利用双波浪线的这个属性将 NaN 转换为数字,而且幸运的是,该数字是零!

console.log(~~NaN); // 0


2
谢谢,我之前完全不知道这个 ~~,我只是和 parseFloat() 一起使用,像这样:~~parseFloat($variable);。非常好用 :) +1 - Rens Tillmann
1
警告~~20000000000 会得到 -1474836480 - sidney
1
提醒一下,parseFloat(4.567) 返回 4.567,但 ~~parseFloat(4.567) 返回 4,因此它丢失了小数部分和小数点。 - Baz Guvenkaya

31

编写自己的方法,并在需要数字值的任何地方使用它:

function getNum(val) {
   if (isNaN(val)) {
     return 0;
   }
   return val;
}

1
如果我传入null,它不会给我期望的结果0。更多关于我的观点在这里:https://dev59.com/f3VD5IYBdhLWcg3wBWzd - Andrei Bazanov
2
根据我上面的评论,最终我使用Number(val)代替了原先的方法,因为它在无法解析时返回0。 - Andrei Bazanov
@AndreiBazanov OP要求“将NaN转换为0”。虽然null不是NaN,但您为什么期望它的结果为0呢? - tsh
@AndreiBazanov OP要求“将NaN转换为0”。虽然null不是NaN,但你为什么期望它的结果是0呢? - tsh
@tsh 因为我们正在处理JS,所以任何事情都有可能 :) - Andrei Bazanov

13

任何事情都需要简单而有效的解决方案:

function getNum(val) {
   val = +val || 0
   return val;
}

此方法将把任何“假值”转换为0

“假值”包括:

  • false
  • null
  • undefined
  • 0
  • "" (空字符串)
  • NaN (非数字)

1
有趣!我在想当val可以是负值时它会有何反应。就我测试的情况来看,这没有任何问题,但以防万一... - Luciano

4
不要为了继续运行而使它变得混乱,为什么不回头想一想你为什么会在第一次遇到NaN时出现问题呢?如果任何操作的数字输入中有NaN,则输出也将是NaN。这是当前IEEE浮点标准的工作方式(不仅仅是Javascript)。这种行为是有一个很好的理由的:底层意图是防止您使用错误的结果而没有意识到它是错误的。NaN的工作方式是,如果某个子操作中发生了错误(在该较低级别产生NaN),则最终结果也将是NaN,即使您的错误处理逻辑(throw / catch可能?)尚未完成,您也会立即认识到这是一个错误。
算术计算的结果为NaN始终表示算术细节出了问题。这是计算机说“需要调试”的一种方式。与其找到一些方式以任何情况下都不正确的数字继续进行(0真的是你想要的吗?),为什么不找到问题并修复它呢?
Javascript中常见的问题是,如果给定无意义的参数(null,''等),parseInt(...)和parseFloat(...)都会返回NaN。尽可能在最低级别上解决问题,而不是在更高的级别上解决问题。然后,整个计算的结果有很好的机会是有意义的,而且您不会为整个计算结果替换一些魔术数字(0或1或其他数字)。((parseInt(foo.value)|| 0)的技巧仅适用于总和,对于乘积,您希望默认值为1而不是0,但前提是指定的值确实为0。)
也许为了编码方便,您想要一个函数从用户那里检索值,清理它,并在必要时提供默认值,像这样:
function getFoobarFromUser(elementid) {
        var foobar = parseFloat(document.getElementById(elementid).innerHTML)
        if (isNaN(foobar)) foobar = 3.21;       // default value
        return(foobar.toFixed(2));
}

3

我建议您使用正则表达式(regex):

const getNum = str => /[-+]?[0-9]*\.?[0-9]+/.test(str) ? parseFloat(str) : 0;

以下代码将忽略NaN,以允许正确输入数字的计算:

const getNum = str => /[-+]?[0-9]*\.?[0-9]+/.test(str) ? parseFloat(str) : 0;

const inputsArray = [...document.querySelectorAll('input')];

document.getElementById("getTotal").addEventListener("click", () => {
  let total = inputsArray.map(fld => getNum(fld.value)).reduce((a,b)=>a+b);
  console.log(total)
});
<input type="text" />
<input type="text" />
<input type="text" />
<input type="text" disabled />
<button type="button" id="getTotal">Calculate</button>


3

如果你试图使用parseInt(),那么使用isNaN的方法是无效的。例如:

parseInt("abc"); // NaN
parseInt(""); // NaN
parseInt("14px"); // 14

但是在第二种情况下,isNaN会返回false(即空字符串被视为数字)。
n="abc"; isNaN(n) ? 0 : parseInt(n); // 0
n=""; isNaN(n) ? 0: parseInt(n); // NaN
n="14px"; isNaN(n) ? 0 : parseInt(n); // 14

简而言之,null字符串在isNaN函数中被视为有效数字,但在parseInt函数中不被视为有效数字。这一点已经通过在macOS v10.14 Mojave上使用Safari、Firefox和Chrome进行验证。


1
一个明显的解决方案有点麻烦,在parseInt之后检查NaN,而不是在之前:isNaN(parseInt(n))?parseInt(n):0; //调用了两次parseInt :( - David Crowe
1
那个注释应该成为您回答的(开端)! - frandroid
一种更有效的解决方案假设空字符串是唯一的异常情况:n=="" || isNaN(n) ? 0 : parseInt(n); (但如果还有其他字符串呢?) - David Crowe

2

NaN是JavaScript中唯一不等于自身的值,所以我们可以利用这个信息:

const x = NaN;
let y = x!=x && 0;
y = Number.isNaN(x) && 0

我们也可以使用Number.isNaN代替isNaN函数,因为后者将其参数强制转换为数字

isNaN('string')        // true which is incorrect because 'string'=='string'
Number.isNaN('string') // false

为什么 "NaN" 被奇怪地进行语法高亮? 语法高亮器是否正确? - Peter Mortensen
可能是语法高亮器出了问题 - “全局NaN属性是表示非数字的值。... NaN是全局对象的一个属性。” 为什么会这样?使用“Number.NaN”怎么样? - Peter Mortensen

1
请尝试这个简单的函数。
var NanValue = function (entry) {
    if(entry=="NaN") {
        return 0.00;
    } else {
        return entry;
    }
}

需要解释一下。例如,这个想法/要点是什么?它与以前的答案有何不同(有些使用isNaN())?它在哪些输入方面失败了?根据帮助中心的说法:“...始终解释为什么您提出的解决方案是合适的以及它是如何工作的”。请通过编辑(更改)您的答案来回应,而不是在此处发表评论(不包括“Edit:”,“Update:”或类似内容 - 答案应该看起来像今天写的)。 - Peter Mortensen

1

    var i = [NaN, 1,2,3];

    var j = i.map(i =>{ return isNaN(i) ? 0 : i});
    
    console.log(j)


需要解释一下。例如,什么是主意/要点?来自 帮助中心 的内容:“...总是解释为什么你呈现的解决方案是合适的以及它如何工作”。请通过编辑(更改)您的答案进行回应,不要在评论中回复(不需要 “Edit:”,“Update:”或类似的文字 - 答案应该看起来像今天写的)。 - Peter Mortensen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接