本文为读 lodash 源码的第二百五十六篇,后续文章会更新到这个仓库中,欢迎 star:pocket-lodash
gitbook也会同步仓库的更新,gitbook地址:pocket-lodash
createRound 用来创建类似于 Math.round 、Math.ceil 之类的舍入取整方法。
Math.round 之类的原生方法,经过转换后会是一个整数,但是 createRound 可以根据精度取整。
例如使用 createRound 创建一个 ceil 方法:
const ceil = createRound('ceil')
ceil(6.004, 2) // => 6.01
ceil(6040, -2) // => 61006.004,因为指定精度是 2 ,而且是向上取整,因此得到的是 6.01 。
6040 因为指定的精度为 -2 ,因此从小数点往前数(这里没有小数点,或者说小数点在最后一位)两位,即到 60 处,下一位是 4 ,向上取整得到 6100 。
源码如下:
function createRound(methodName) {
const func = Math[methodName]
return (number, precision) => {
precision = precision == null ? 0 : (precision >= 0 ? Math.min(precision, 292) : Math.max(precision, -292))
if (precision) {
let pair = `${number}e`.split('e')
const value = func(`${pair[0]}e${+pair[1] + precision}`)
pair = `${value}e`.split('e')
return +`${pair[0]}e${+pair[1] - precision}`
}
return func(number)
}
}methodName 是指要创建什么样的方法,对应 Math 中的 round 、ceil 和 floor 等。
先用 Math[methodName] 将 Math 中对应的方法 func 取出。
可以看到,调用 createRound 最终会返回一个方法,可以将 createRound 理解为一个工厂方法。
precision = precision == null ? 0 : (precision >= 0 ? Math.min(precision, 292) : Math.max(precision, -292))如果没有传入精度,则精度为 0 ,这跟直接调用 Math 对应方法的效果一样。
如果 percision 为正数,则取 292 和 precision 的较小者,因为后面会对 number 做放大操作,如果最大值 Math.MAX_VALUE 和 1e292 相加,会得到 INFINITY。
同理,如果 precision 小于 0 ,则取 -292 和 precison 中的较大者。
在精度为 0 的情况下,直接调用 func[number] ,没有做任何转换,其实和直接调用 Math 上对应的方法没有任何差别。
let pair = `${number}e`.split('e')
const value = func(`${pair[0]}e${+pair[1] + precision}`)因为 Math 的函数只能处理整数,因此要精确到小数位和支持负精度,需要对 number 进行缩放。
缩放本来很简单,只需要这样即可:
number * 10 * precision但是如果是浮点数,在进行乘法运算时,可能会出现精度丢失的情况。
因此这里使用了一种比较迂回的方式,先将数字转换成字符串,使用字符串科学记数法拼接的方式来进行缩放,再传给 func 转换。
pair 得到的是类似这样的数组 [有效数, 位数, ''] ,因此只需要对位数进行缩放即可。
也即使用科学记数法,放大后的科学记数法字符串是 ${pair[0]}e${+pair[1] + precision} 。
在这里就可以调用 func 得到缩放取整后的结果。
pair = `${value}e`.split('e')
return +`${pair[0]}e${+pair[1] - precision}`因为在取整的时候是要进行缩放的,在取整得到结果后,需要反向缩放,才能得到真正的结果。
反向缩放的原理和上面的一样。
https://www.cnblogs.com/xiaohuochai/p/5586166.html
https://www.cnblogs.com/zhoulujun/p/10880912.html
署名-非商业性使用-禁止演绎 4.0 国际 (CC BY-NC-ND 4.0)
最后,所有文章都会同步发送到微信公众号上,欢迎关注,欢迎提意见: 
作者:对角另一面