Lodash toNumber Hexadecimal Prefix Handling
The Lodash _.toNumber method converts values into
numbers through a structured pipeline that cleans input strings,
normalizes custom objects, and validates base-prefixed numeric
representations. While binary (0b) and octal
(0o) prefixes are explicitly stripped via string slicing,
hexadecimal prefixes (0x or 0X) are processed
through a combination of regex pattern validation for invalid signed
variants and JavaScript's native numeric coercion mechanism. This
article breaks down the internal source code mechanics of Lodash to
demonstrate exactly how hexadecimal inputs are validated, parsed, and
converted.
Input Sanitization and Normalization
Before inspecting any number format, _.toNumber
processes non-primitive inputs and cleans whitespace:
- Object Unwrapping: If the input is an object,
Lodash attempts to invoke its
.valueOf()method. If the result remains an object, it falls back to string coercion using template literals. - Type Checking: If the processed value is not a
string, Lodash returns symbols as
NaNor coerces primitives directly using unary+value. - Trimming: For string inputs, Lodash applies the
reTrimregular expression (/^\s+|\s+$/g) to strip leading and trailing whitespace characters.
The Contrast: Explicit Slicing in Binary and Octal
To understand how hexadecimal values are handled, it helps to observe how binary and octal strings are treated in the Lodash source code:
const reIsBinary = /^0b[01]+$/i;
const reIsOctal = /^0o[0-7]+$/i;
const isBinary = reIsBinary.test(value);
return (isBinary || reIsOctal.test(value))
? parseInt(value.slice(2), isBinary ? 2 : 8)
: (reIsBadHex.test(value) ? NAN : +value);For binary and octal literals, Lodash systematically removes the
two-character prefix (0b or 0o) using
value.slice(2) and routes the remaining digits into
parseInt with an explicit radix of 2 or
8.
Hexadecimal
Handling: The reIsBadHex Filter
Unlike binary and octal numbers, hexadecimal strings are not stripped
using .slice(2). Instead, Lodash implements a validation
guard against invalid hexadecimal formats using the
reIsBadHex regular expression:
const reIsBadHex = /^[-+]0x[0-9a-f]+$/i;In standard JavaScript syntax, signed hexadecimal string literals
such as "-0x1a" or "+0x1a" are not valid
numerical representations in modern ECMAScript specifications, causing
unary + to return NaN, whereas legacy parsers
such as parseInt might have yielded -26.
By testing the trimmed string against reIsBadHex, Lodash
guarantees that any signed hexadecimal input explicitly evaluates to
NaN across all JavaScript runtimes:
reIsBadHex.test(value) ? NAN : +valueDelegation to the ECMAScript Engine
When a string contains a valid, unsigned hexadecimal prefix
(0x or 0X), it bypasses the
reIsBadHex branch and reaches the fallback expression:
+value.
At this stage, the task of stripping the prefix and computing the
base-16 value is systematically handled by the JavaScript engine's
internal ToNumber abstract operation:
- The runtime parser encounters a string conforming to the ECMAScript
HexIntegerLiteralgrammar:0xor0Xfollowed by one or more hexadecimal digits ([0-9a-fA-F]). - The engine's lexical scanner recognizes the
0x/0Xcharacters as a base-16 indicator rather than part of the numeric value. - The prefix is internally discarded, and the remaining characters are computed using positional base-16 mathematics (\(d \times 16^n\)).
Summary
Lodash's _.toNumber systematically isolates hexadecimal
prefix handling from octal and binary conversions. Instead of manually
invoking string-slicing methods to remove 0x, Lodash cleans
the string, ensures that signed variants are flagged as
NaN, and delegates the removal of the 0x
prefix directly to the JavaScript engine's native string-to-number
coercion.