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:
- Direct Numbers: If the input is already a number primitive, it is returned immediately.
- Symbols: JavaScript Symbols cannot be coerced to
numbers;
_.toNumbersafely returnsNaNinstead of throwing aTypeError. - Objects: If the value is an object, Lodash checks
if it has a custom
valueOfmethod. If present, it unwraps the object (e.g.,new String("42")becomes"42"). IfvalueOfreturns another object, it falls back to callingtoString().
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:
- Binary: Matches patterns starting with
0bor0Bfollowed by digits0and1(e.g.,"0b1010"). Lodash extracts the slice after the prefix and usesparseInt(value.slice(2), 2)to calculate the decimal equivalent (10). - Octal: Matches patterns starting with
0oor0Ofollowed by digits0through7(e.g.,"0o755"). Lodash slices the prefix and callsparseInt(value.slice(2), 8).
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:
- Unsigned Hexadecimal: If the string starts with
0xor0X(e.g.,"0xff"), Lodash parses it usingparseInt(value.slice(2), 16)to return255. - Standard Floats and Scientific Notation: For all
other values—including decimal numbers (
"3.14"), exponential notation ("1e5"), and negative values ("-42.5")—Lodash uses the native unary plus operator (+value).
Summary of Parsing Order
- Return if primitive number; return
NaNifSymbol. - Extract primitive value from objects via
valueOfortoString. - Trim surrounding whitespace.
- If binary (
/^0b[01]+$/i), parse with base 2. - If octal (
/^0o[0-7]+$/i), parse with base 8. - If signed hex (
/^[-+]0x[0-9a-f]+$/i), returnNaN. - If unsigned hex (
/^0x[0-9a-f]+$/i), parse with base 16. - Coerce remaining formats via unary
+(supporting standard decimals, scientific notation, and empty strings).