lodash里的toNumber方法

613 阅读3分钟

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

使用说明

toNumber方法目的是将数据转换为数字类型,而实际上该方法的使用率非常高,实际项目中我们常常调用隐式转换去转换数字类型,而对于极端情况我们并不是很在意。

_.toNumber(3.2);
// => 3.2
 
_.toNumber(Number.MIN_VALUE);
// => 5e-324
 
_.toNumber(Infinity);
// => Infinity
 
_.toNumber('3.2');
// => 3.2

_.toNumber()
// => NaN

_.toNumber(()=>{})
// => NaN

手动实现

对于实现一个number方法,我们可以做如下处理:

function toNumber(number){
    return +number
}

该方法实现主要运用了+操作符的隐式转换,直接转换为数字类型。

源码实现

lodash里的toNumber方法封装,内部主要是针对极端情况的非目标类型进行特殊处理。

/**  用作各种 `Number` 常量的引用 */
var NAN = 0 / 0;

/** 用于检测错误的有符号十六进制字符串值 */
var reIsBadHex = /^[-+]0x[0-9a-f]+$/i;

/** 用于检测二进制字符串值 */
var reIsBinary = /^0b[01]+$/i;

/** 用于检测八进制字符串值 */
var reIsOctal = /^0o[0-7]+$/i;

var freeParseInt = parseInt;

function toNumber(value) {
  if (typeof value == 'number') {
    return value;
  }
  if (isSymbol(value)) {
    return NAN;
  }
  if (isObject(value)) {
    var other = typeof value.valueOf == 'function' ? value.valueOf() : value;
    value = isObject(other) ? (other + '') : other;
  }
  if (typeof value != 'string') {
    return value === 0 ? value : +value;
  }
  value = baseTrim(value);
  var isBinary = reIsBinary.test(value);
  return (isBinary || reIsOctal.test(value))
    ? freeParseInt(value.slice(2), isBinary ? 2 : 8)
    : (reIsBadHex.test(value) ? NAN : +value);
}

toNumber方法在实现上,对于数字类型直接返回参数,而symbol类型返回NaN。

对象类型的话则进行如下处理,主要针对对象类型的数据:

  • 先判断源数据参数身上的valueOf 方法是否存在,即判断valueOf 方法是否是一个函数,是对的话调用该方法并将结果存储起来,否则的话将源数据存储起来。
  • 对于存储的结果,在对其进行判断,如果是对象类型,直接将第一步存储的结果转换为字符串,不是对象的话则返回第一步存储的结果。

对于非字符串类型的数据,先判断其是否等于0,是的话直接返回,否则的话返回隐式转换之后的结果。

上面的处理主要是针对特例进行if判断处理,主要针对了数字类型、symbol类型、对象类型以及非字符串类型,其余类型则在函数执行流程中处理。

可以看到在其余类型的处理如下:

  • 先是处理参数,调用baseTrim方法,主要是去除字符串中头尾空格。
  • 如果参数是二进制字符串值或八进制字符串值,调用freeParseInt方法。
  • 如果参数是十六进制字符串值,则返回NaN,否则其他情况返回参数的隐式转换值。
var reWhitespace = /\s/;

// 匹配最后一个空白字符的索引
function trimmedEndIndex(string) {
  var index = string.length;

  while (index-- && reWhitespace.test(string.charAt(index))) {}
  return index;
}

var reTrimStart = /^\s+/;

// 去除头尾的空白空格
function baseTrim(string) {
  return string
    ? string.slice(0, trimmedEndIndex(string) + 1).replace(reTrimStart, '')
    : string;
}

小结

lodash的toNumber在实现上考虑到参数的多种情况,重点处理字符串的进制问题。

其次对于对象类型,则调用对象身上的valueOf方法。

对于symbol类型则返回NaN,数字类型直接返回参数。