ES2015 为 Math
对象扩展了 trunc
方法,旨在用于去除一个数的小数部分。
在此之前处理去除小数位这一项任务时,我们通常使用 parseInt
和 Math.ceil
、Math.floor
这三个方法。
一个方法的一定是为了解决开发痛点而出现的,在此之前的这三个方法,各自存在哪些问题?
parseInt
parseInt
其返回值只有两种可能: 十进制整数 或 NaN
。 其去除小数位的工作原理本质上是遇到非数字字符,即 .
时停止解析,提取已解析部分。
它存在多种处理规则,处理数据时会得到许多不符合期望的结果。
Number.parseInt
是挂载到Number
对象上的静态方法,而parseInt
是全局对象上的方法,两者功能相同,这里仅对parseInt
进行讨论。
转换非数字字符串
parseInt
在对目标字符串进行转换时,会从左到右查看,遇到非数字字符后停止,并提取数字部分。因此存在会转换非数字字符串的问题。
1 | parseInt( "114.514g" ); // 114 |
因此对于小数的省略写法 .xx
,parseInt
会得到 NaN
,而 Math.trunc
则会得到正确结果 0
。
1 | parseInt( ".514" ); // NaN |
自动识别进制解析方式
默认不传递第二个参数时,parseInt
会尝试将目标字符串按照十进制解析。
但是当目标字符串以 0x
或 0X
开头时,parseInt
会尝试将其按照十六进制来解析。
1 | parseInt( "0xA0" ); // 160 |
而 8
进制就得不到这种特殊待遇了,parseInt
在不同浏览器上对于 8
进制数字字符串的解析规则不同,
有的会自动识别 8
进制,有的则不会。
因此需要手动传入第二个参数来保证解析 8
进制。
1 | parseInt( "010" ); // 10 |
但 parseInt
还有一个特性,即当接受的第一个参数不是字符串时,会自动调用 toString
方法将其转换为字符串。
这对于 8
进制数字的字符串来说,会导致错误的结果。
1 | parseInt( "011", 8 ); // 9 |
错误转换科学计数法
当整数位数超过 22
位或小数位存在连续 6
个 0 时,将会自动以科学计数法展示,此时使用 parseInt
转换时会出现问题
1 | let num = 3000000000000000000000.114; // 此时被直接解析为 3e+21 |
稍微提一嘴,
parseFloat
并不会出现这种结果,而是直接返回科学计数法的结果
Math.ceil 与 Math.floor
Math.ceil
向上取整,可针对负数起到去除小数位的作用,正数则不可以。Math.floor
与其相反。
因此在 Math.trunc
出现之前,若使用 Math.ceil
与 Math.floor
实现去除小数位,需要这样编写:
1 | function getInteger( num ) { |
Math.trunc
Math.trunc
则使得去除小数位的操作变得简单,不需要考虑正负号、进制、科学计数法等问题,直接使用即可。
1 | Math.trunc( 114.514 ); // 114 |
需要注意的是,当第一个参数不是数字类型时,Math.trunc
会自动调用 Number()
方法将其转换为数字类型,
而 Number()
方法是不会将传统八进制字符串(0xx
)按照 8 进制解析的,使用 0oxx
方式的八进制字符串才会正常按照 8 进制解析,因此会有如下结果:
1 | Math.trunc( 010 ); // 8 |