lodash源码解读之floor

866 阅读2分钟

方法介绍

lodash中的floor方法的作用跟Math.floor类似,但是其接受两个参数:_.floor(number,[precision=0])

  • number 就是要取舍的值
  • precision 就是向下取舍的精度,按官方的解释就是,可以理解为保留几位小数,这也是跟Math.floor有区别的地方

源码讲解

import createRound from './.internal/createRound.js'

/**
 *
 * floor(4.006)
 * // => 4
 *
 * floor(0.046, 2)
 * // => 0.04
 *
 * floor(4060, -2)
 * // => 4000
 */
const floor = createRound('floor')

export default floor

源码中可以看到,其主要的就是一个createRound函数,看下createRound函数内部代码:

/**
 * Creates a function like `round`.
 *
 * @private
 * @param {string} methodName The name of the `Math` method to use when rounding.
 * @returns {Function} Returns the new round function.
 */
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)
  }
}

export default createRound

在createRound函数内部,返回了一个函数,该函数也就是lodash的floor方法的主体了

  • func = Math[methodName],我们传入的是floor,所以func就是Math.floor
  • precision == null,双等号非严格等于,所以precision可能是undefiend和null,此时,为precision赋值0,在看后面的表达式,就是precision的取值范围在 -292 - 292之间
  • 如果precision为0的话,就直接返回 func(number),也就是Math.floor(number) 如果传入了精度值precision,进入到条件判断内部
  • 先定义一个数组(let pair = ${number}e.split('e')),其值为[number,''],不过此时的number类型为字符串了
const number = 4.006;
`${number}e`.split('e')  //['4.006','']
  • 调用func(Math.floor)方法,${pair[0]}e${+pair[1] + precision}就是将number乘以10的precision次方,例如传入的number是4.006,precision是2,'4.006e2',科学计数法,就是4.006*10^2,此时得到的value值就是一个放大了10的precision次方被的整数(例子中就是400)
${pair[0]}e${+pair[1] + precision}  //4.006e2 === 400.6
const value = Math.floor(4.006e2)  //400
  • ${value}e.split('e'),又将value同之前的number一样,搞成一个数组赋值给pair,其值是[value,''],value的类型是字符串
pair = `${value}e`.split('e')  // '400e'.split('e') == ['400','']
  • 最后,return +${pair[0]}e${+pair[1] - precision},字符串模版里面的,就跟上面得到value时的字符串模板一样,不同的是,上面是+precision,这里是-precision,也就是,如果上面是乘以10^2,这里就是除以10^2了(乘以10^-2),也就是前面如果放大了,这里就需要缩小了,如果precision是负数呢,前面是缩小,这里就该放大了,还原number;前面的+就是利用隐式类型转换,将字符串转为数字了
`${pair[0]}e${+pair[1] - precision}`  //'400e-2'
+'400e-2'  //400e-2 === 4

这里总结个疑问:

  • 为什么每次都是将number或则value搞成一个数组,在下次的字符串拼接中在取数组的下标 换成数组再使用下标,或则是直接使用${number}来代替pair[0],是一样的,没有任何区别,应该只是个人写法的问题