How Lodash _.toNumber Parses Complex Strings

The _.toNumber method in Lodash is designed to safely convert arbitrary JavaScript values, particularly complex string representations, into standard numbers. Unlike native Number() or parseFloat(), Lodash standardizes cross-environment quirks by actively sanitizing strings, detecting non-decimal radices like binary and octal, rejecting signed hexadecimal patterns, and gracefully unwrapping objects. This guide explains the step-by-step logic Lodash uses under the hood to parse complex string formats into valid numeric values or NaN.

1. Object Unwrapping and Type Guarding

Before parsing strings, _.toNumber evaluates the incoming value's underlying type:

2. Whitespace Stripping

Once the value is guaranteed to be a string primitive, Lodash removes all leading and trailing whitespace using a regular expression equivalent to String.prototype.trim(). This ensures that trailing spaces or tabs around complex numbers do not cause parsing failures downstream.

3. Detection of Non-Decimal Notations (Binary and Octal)

Lodash contains explicit regular expressions to test for ES6 binary and octal string literals:

If either regex matches, Lodash parses the string with the corresponding base and returns the result, bypassing standard string conversion.

4. Guarding Against Signed Hexadecimal

A key divergence between Lodash and native JavaScript coercion involves signed hex strings. Lodash tests strings against a specific bad-hex pattern: /^[-+]0x[0-9a-f]+$/i.

While standard hexadecimal literals like "0x1a" are accepted, signed hex representations such as "+0x1a" or "-0x1a" match the "bad hex" regular expression. When this pattern is detected, _.toNumber intentionally returns NaN. This behavior ensures cross-browser consistency with older ECMAScript specifications that treated signed hex literals as invalid.

5. Standard Hexadecimal and Decimal Fallback

If the string is not binary, not octal, and not an invalid signed hex, Lodash evaluates standard hex or decimal notations:

Summary of Parsing Order

  1. Return if primitive number; return NaN if Symbol.
  2. Extract primitive value from objects via valueOf or toString.
  3. Trim surrounding whitespace.
  4. If binary (/^0b[01]+$/i), parse with base 2.
  5. If octal (/^0o[0-7]+$/i), parse with base 8.
  6. If signed hex (/^[-+]0x[0-9a-f]+$/i), return NaN.
  7. If unsigned hex (/^0x[0-9a-f]+$/i), parse with base 16.
  8. Coerce remaining formats via unary + (supporting standard decimals, scientific notation, and empty strings).