Search code examples
javascriptlodashparseint

What's the difference between lodash toNumber and parseInt?


I know Lodash often adds some extra checks or niceties to functions that already exist in JavaScript but it's not clear what _.toNumber specifically does that I wouldn't get with parseInt.

I'd prefer to use Lodash only when it provides benefits that aren't there with existing JavaScript functions but I can't see any in this case.


Solution

  • I think it is much better to simply look at the _.toNumber source and that would practically answer your question:

    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 = value.replace(reTrim, '');
      var isBinary = reIsBinary.test(value);
      return (isBinary || reIsOctal.test(value))
        ? freeParseInt(value.slice(2), isBinary ? 2 : 8)
        : (reIsBadHex.test(value) ? NAN : +value);
    }
    

    As you can see it does a bunch of other things in comparison to parseInt. To be more specific:

    console.log(_.toNumber(1),       parseInt(1))        // same 
    console.log(_.toNumber('1'),     parseInt('1'))      // same  
    console.log(_.toNumber('b'),     parseInt('b'))      // same  
    console.log(_.toNumber({}),      parseInt({}))       // same 
    console.log(_.toNumber(' 1 '),   parseInt(' 1 '))    // same
    console.log(_.toNumber([1]),     parseInt([1]))      // same
    console.log(_.toNumber(' 1a1 '), parseInt(' 1a1 '))  // NaN      1
    console.log(_.toNumber([1,2]),   parseInt([1,2]))    // NaN      1
    console.log(_.toNumber(false),   parseInt(false))    // 0        NaN
    console.log(_.toNumber(!0),      parseInt(!0))       // 1        NaN
    console.log(_.toNumber(!!0),     parseInt(!!0))      // 0        NaN
    console.log(_.toNumber(5e-324),  parseInt(5e-324))   // 5e-324   5
    console.log(_.toNumber(5.5),     parseInt(5.5))      // 5.5      5
    console.log(_.toNumber(null),    parseInt(null))     // 0        NaN
    console.log(_.toNumber(Infinity),parseInt(Infinity)) // Infinity NaN
    <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

    So to summarize _.isNumber gives you more expected / consistent and I would argue safer results when it comes to parsing input with arrays, decimals, falsy values and strings. It would check the entire input vs parseInt which only cares about the first valid value as you can see from the examples above. It also handles better the negate operator (!) etc.

    So overall it does have its uses vs parseInt

    Note: What is a gotcha here is that both _.toNumber and parseInt return NaN for undefined which considering how _.toNumber deals with the rest of the falsy values one would expect to return 0 vs NaN:

    console.log(_.toNumber(undefined), parseInt(undefined))  // NaN NaN