在JavaScript中使用parseInt进行字符串转整数时,若字符串以0开头且未指定radix参数,引擎可能将其解析为八进制数,导致08和09转换结果为0。本文详解该机制,并推荐始终传入10作为第二个参数以强制十进制解析,避免日期验证等场景下的潜在Bug。
parseInt 前导零导致的八进制解析陷阱
为了在客户端验证表单中填写的日期格式,网上找到了一段示例代码,其中使用parseInt对年、月、日进行判断,包含类似这样的语句:
......
else if(parseInt(month)<1 || parseInt(month) >12)
......
然而,对于原本正确的日期,该判断始终无法通过。经排查发现,parseInt函数实际上接受两个参数:第一个是待转换的值,第二个是指定的进制基数。若省略第二个参数,该函数仅能正确将01到07转换为1到7;从08开始,它会遵循“以0开头的字符串被视为八进制数”的规则进行转换。恰好当前是9月,随手选择的日期暴露了此问题;若在上半年测试,此Bug可能会潜伏至下半年才被客户发现。
因此,将函数中所有涉及parseInt的地方均补充了第二个参数,明确指定为十进制。例如上述语句修改为:
......
else if(parseInt(month,10)<1 || parseInt(month,10) >12)
......
问题复现与 API 机制解析
此前多次在JavaScript中使用parseInt将字符串转换为数字时遇到问题,当时便改用其他方法进行比较。
当从页面获取日历控件的值并转换为数字进行比较时,月份的转换经常出现问题。
当我使用
var num = parseInt(01);
var num = parseInt(01);
...
var num = parseInt(07);
var num = parseInt(08);
var num = parseInt(09);
var num = parseInt(10);
假如进行如上转换时,
parseInt()传入的参数从1到7均无问题,但当使用parseInt(08)时出现异常,转换后的num值为0。
当时因项目紧急,未深入追究原因。
现有空闲时间重新审视parseInt这一JavaScript方法。
JavaScript API文档说明如下:
parseInt 方法
返回由字符串转换得到的整数。
parseInt(numString, [radix])
参数
numString
必选项。要转换为数字的字符串。
radix
可选项。在 2 和 36 之间的表示 numString 所保存数字的进制的值。如果没有提供,则前缀为 '0x' 的字符串被当作十六进制,前缀为 '0' 的字符串被当作八进制。所有其它字符串都被当作是十进制的。
阅读上述API可知,当传入参数为01到08时,因参数以'0'开头,系统将其转换为八进制。由于八进制仅能表示0到7,故01到07转换正确,而08发生进位错误,转换为0。parseInt(10)则能正确转换为10。
解决方案:显式指定 radix 参数
因此,规范的做法是不省略最后一个参数。
使用parseInt(08,10);即可正确转换。