lodash里的ceil

304 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第6天,点击查看活动详情

方法说明

同Math.ceil方法一样,lodash里的ceil方法可以根据精度向上舍入,不同于原生的Math.ceil,lodash的ceil方法可以接收两个参数,第一个参数为数据源,第二个参数为可选参数,表示保留的位数。

两个参数以及返回值的数据类型均为数字类型。

具体用法如下:

_.ceil(4.006);
// => 5
 
_.ceil(6.004, 2);
// => 6.01
 
_.ceil(6040, -2);
// => 6100

虽然官网说明中指定的第一个参数为数字类型,但是我们依旧可以传入非数字类型:

_.ceil('1',2)
// => 1

_.ceil('1.3',2)
// => 1.3

_.ceil('1.3442',2)
// => 1.35

_.ceil('1.344s',2)
// => NaN

_.ceil([1,2,3],2)
// => NaN

可见其内部也是做了很多兼容处理。

源码实现

第一步,在没有精度的情况下(即没有第二个参数),我们直接调用原生的ceil方法即可:

function ceil(number){
    return Math.ceil(number)
}

第二步,当存在精度参数的时候,我们要根据精度参数进行处理:

function ceil(number,precision){
    if(precision){
        let pair = `${number}e`.split('e')
        const value = Math.ceil(`${pair[0]}e${+pair[1] + precision}`)
        pair = `${value}e`.split('e')
        return +`${pair[0]}e${+pair[1] - precision}`
    }
    return Math.ceil(number)
}

在这里的精度处理很巧妙,上述代码正是lodash里ceil方法对于精度的处理,我们可以看到其先是将源数字直接转换为字符串,然后拼接上字符串e。

在js中,大数据会通过科学计算法计数,带参数e,而我们通过字符分割也可以很好的处理大数字的参数部分,而无论我们传入的参数是否是大数字(大数字带e),我们取分割后的首个索引对应的值就是正确的。

输出结果则通过隐式类型转换。

上述代码正是ceil实现的核心,源码部分依旧通过工厂函数创建,并附带部分处理逻辑,在工厂函数里则通过保存Math身上的方法,在内部进行调用。(为什么是工厂函数?因为这部分的代码逻辑可以在后续的某些方法中复用。)

同时在实现上,依旧需要进行严谨性判断处理,精度范围限制在292位。

 precision = precision == null ? 0 : (precision >= 0 ? Math.min(precision, 292) : Math.max(precision, -292))

下面为ceil全部的源码实现:

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)
 }
}

const ceil = createRound('ceil')

export default ceil

小结

lodash源码对于实现ceil方法,是在原生的Math.ceil方法进行拓展,增加了精度控制处理。

源码实现上依旧遵循工厂函数返回,严谨性判断等。

此部分代码的核心在于精度控制处理,采用转字符串配合参数e切割处理,十分巧妙。