看代码:

alert(parseInt(0.000001));

alert(parseInt(0.0000001));


第一条语句输出 0, 第二条语句输出 1, 囧。


继续看代码:

alert(parseInt('0.000001'));

alert(parseInt('0.0000001'));


都输出 0, 这才符合预期。


查看 ECMA-262 规范,parseInt 会先调用 toString 方法。问题已逐渐清晰:

alert(0.000001);

alert(0.0000001);


第一条语句原样输出,第二条语句输出 1e-7.

继续翻查 ECMA-262 9.8.1 ToString Applied to the Number Type 一节,恍然大悟:

assertEquals("0.00001", (0.00001).toString());

assertEquals("0.000001", (0.000001).toString());

assertEquals("1e-7", (0.0000001).toString());

assertEquals("1.2e-7", (0.00000012).toString());

assertEquals("1.23e-7", (0.000000123).toString());

assertEquals("1e-8", (0.00000001).toString());

assertEquals("1.2e-8", (0.000000012).toString());


上面是 V8 引擎 number-tostring 的单元测试脚本, 很好地诠释了 ECMA 规范。


小结:对于小于 1e-6 的数值来说,ToString 时会自动转换为科学计数法。因此 parseInt 方法,在参数类型不确定时,最好封装一层:

function parseInt2(a) {

   if(typeof a === 'number') {

       return Math.floor(a);

   }

   return parseInt(a);

}