为什么 JavaScript 的 parseInt(0.0000005) 打印“5”?

Sey*_*don 65 javascript type-conversion parseint node.js typescript

我读过一篇关于JavaScript parseInt 的文章,其中有这个问题:

parseInt(0.5);      // => 0
parseInt(0.05);     // => 0
parseInt(0.005);    // => 0
parseInt(0.0005);   // => 0
parseInt(0.00005);  // => 0
parseInt(0.000005); // => 0

parseInt(0.0000005); // => 5
Run Code Online (Sandbox Code Playgroud)

为什么会发生这种情况?

Sey*_*don 109

基于ecmascript 标准

\n
\n

parseInt函数根据指定的基数Number生成由参数内容解释决定的积分。string

\n
\n

第 1 部分 - 转换0.0000005string

\n

parseInt函数的第一步是将输入转换为字符串(如果不是):

\n
\n

19.2.5 parseInt(字符串,基数)

\n

当调用parseInt函数时,会执行以下步骤:

\n
    \n
  1. Let inputString be ? ToString(string).
  2. \n
  3. 让S成为吧!TrimString(输入字符串,开始)。
  4. \n
\n

...

\n
\n

在每种情况下,字符串输出如下:

\n
String(0.5);      // => \'0.5\'\nString(0.05);     // => \'0.05\'\nString(0.005);    // => \'0.005\'\nString(0.0005);   // => \'0.0005\' \nString(0.00005);  // => \'0.00005\'\nString(0.000005); // => \'0.000005\'\n\nString(0.0000005); // => \'5e-7\'\n
Run Code Online (Sandbox Code Playgroud)\n

第 2 部分 - 转换5e-7integer

\n

因此,这意味着当我们使用 时parseInt(0.0000005),它等于parseInt(\'5e-7\')并基于定义:

\n
\n

parseInt只能将字符串的前导部分解释为整数值;它忽略任何不能被解释为整数表示法一部分的代码单元,并且没有给出任何此类代码单元被忽略的指示。

\n
\n

因此,答案只会返回5,因为它是唯一一个在非字符之前是数字的字符e,因此其余部分e-7将被丢弃。

\n

感谢@jcalz,我应该提到:

\n
\n

不要使用parseInt(x)不是xxe2x80x99t 的string. 如果你已经有了number大概你想要的Math.round()东西Math.floor()

\n
\n


Tho*_*ann 9

(这更像是一个长评论,而不是一个竞争性的答案。)

导致这种奇怪效果的不需要的转换仅在将值作为parseInt数字类型传递时才会发生 - 在这种情况下,编译器(或解释器或任何驱动 JS 的东西)似乎会自动将数字转换为字符串,作为字符串type 是函数参数的预期类型

不幸的是,数字到字符串的转换函数更喜欢工程数字格式,否则会变得太长。

此外,转换可能会导致精度损失,这是每个程序员在处理十进制(非整数)数字时都必须注意的事情。

如果您记得自己将要解析的值放入字符串中,那么您将不会得到这样的意外结果:

let n = '0.0000005';
console.log(parseInt(n))
Run Code Online (Sandbox Code Playgroud)

将根据需要打印 0。

得到教训:

  • 尽可能避免隐式类型转换。
  • 避免使用parseInt类似的函数,这些函数不会让您知道要解析的字符串是否具有额外的不拟合数据。例如,int 解析“x”或“1x”都应该告诉您这不是一个正确的 int 数字。在这方面,parseInt通过忽略字符串中的额外数据而不告诉我们来表现出不良行为。一个好的解析器函数要么告诉您它停止的位置(以便您可以检查是否有剩余的垃圾),要么在发现意外数据时失败。