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

Why does JavaScript's parseInt(0.0000005) print "5"?

我读过一篇关于 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

为什么会这样?

我在 ecmascript standard 上搜索过它,看到了这个:

第一步是converting the input to `string` if it is not:

19.2.5 parseInt ( string, radix )

The parseInt function is the %parseInt% intrinsic object. When the parseInt function is called, the following steps are taken:

  1. Let inputString be ? ToString(string).
  2. Let S be ! TrimString(inputString, start).

...

因此,我使用 String 函数检查了基于字符串的值,以查看每个值的输出:

String(0.5);      // => '0.5'
String(0.05);     // => '0.05'
String(0.005);    // => '0.005'
String(0.0005);   // => '0.0005' 
String(0.00005);  // => '0.00005'
String(0.000005); // => '0.000005'

String(0.0000005); // => '5e-7'

所以,这意味着当我们使用 parseInt(0.0000005) 时,它等于 parseInt('5e-7') 并且根据定义:

parseInt may interpret only a leading portion of string as an integer value; it ignores any code units that cannot be interpreted as part of the notation of an integer, and no indication is given that any such code units were ignored.

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

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

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

不幸的是,number-to-string 转换函数更喜欢工程编号格式,否则它会变得太长。

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

如果您记得自己将 to-be-parsed 值放入字符串中,那么您就不会得到这样意想不到的结果:

let n = '0.0000005';
console.log(parseInt(n))

将根据需要打印 0。

经验教训:

  • 尽可能避免隐式类型转换。
  • 避免使用 parseInt 和类似的函数,它们不会让您知道要解析的字符串是否有额外的 non-fitting 数据。例如,int-parsing "x" 或 "1x" 都应该告诉你这不是一个正确的整数。在这方面,parseInt 通过忽略字符串中的额外数据而不告诉我们来表现出不良行为。一个好的解析器函数要么告诉你它在哪里停止(这样你就可以检查是否有垃圾遗留下来),要么在它发现意外数据时失败。

请尊重数据类型!

在 Chrome 控制台中:

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");
0
parseInt("0.00000005");
0
parseInt("0.000000005");
0