Lodash _.multiply() method
What you’ll learn
- How
_.multiply(a, b)is justcreateMathOperation((x, y) => x * y, 1)—a thin wrapper around the native*operator. - How
undefinedoperands fall back to the identity1(or the other operand, depending on which side is missing). - Why
_.multiplyis more forgiving with stringy numeric inputs than_.add(no concatenation trap). - That floating-point precision is not fixed:
_.multiply(0.1, 0.2)is still0.020000000000000004. - That
nullcoerces to0and BigInt input throws.
Prerequisites
Skim _.add() first—_.multiply, _.divide, and _.subtract all share the createMathOperation factory. The differences are the operator and the identity element.
- Native
*coercion: always tries to make a number, unlike+which sometimes concatenates. - IEEE-754 floats:
0.1 * 0.2 !== 0.02, and Lodash doesn’t change that.
Overview
The whole function is two lines: createMathOperation((a, b) => a * b, 1). The factory’s undefined-handling rules apply: both undefined → identity (1); one undefined → return the other operand as-is (no multiplication). When both operands are present and at least one is a string, both are run through baseToString—but the * operator then coerces them straight back to numbers, which is why stringy numeric inputs “just work”.
Identity is 1
Different from _.add’s 0. Important for reduce-on-empty patterns.
Native * semantics
No precision tricks, no overflow handling. 0 * Infinity is NaN; -1 * 0 is -0.
BigInt throws
The factory routes through Number(value); BigInt can’t convert. Use the native * operator for BigInt math.
Syntax
_.multiply(multiplier, multiplicand) - multiplier: the first operand.
- multiplicand: the second operand.
- Returns:
number—the product, or the identity / lone operand when one or both areundefined.
Basics & precision
Plain numbers, decimals, and the very large / very small range. Notice the floating-point result for 0.1 * 0.2: Lodash uses native * and inherits IEEE-754 behaviour.
import multiply from "lodash/multiply";
console.log(multiply(6, 4)); // 24 (docs example)
console.log(multiply(5, 3)); // 15
console.log(multiply(0.1, 0.2)); // 0.020000000000000004 (NOT 0.02)
console.log(multiply(19.99, 3)); // 59.97 (lucky; not all decimals land cleanly)
console.log(multiply(1e22, 1e22)); // 1e+44 (scientific notation)
// Currency: scale to integers to dodge precision issues
const cents = multiply(1999, 3);
console.log(cents / 100); // 59.97 undefined, null, and string operands
Three behaviours people get wrong: undefined follows factory rules (identity 1 or the lone operand), null coerces to 0, and stringy numeric inputs are coerced numerically by *—there’s no concatenation trap like _.add has. Non-numeric strings still produce NaN.
import multiply from "lodash/multiply";
// undefined handling (identity = 1)
console.log(multiply(undefined, undefined)); // 1
console.log(multiply(undefined, 5)); // 5 (other operand, no math)
console.log(multiply(5, undefined)); // 5
// null coerces to 0
console.log(multiply(null, null)); // 0
console.log(multiply(5, null)); // 0
// Strings: numeric ones coerce just fine
console.log(multiply("5", 3)); // 15
console.log(multiply("5", "3")); // 15
console.log(multiply("abc", 3)); // NaN (non-numeric string)
// Edge cases inherited from native *
console.log(multiply(0, Infinity)); // NaN
console.log(multiply(-1, 0)); // -0
console.log(multiply(NaN, 5)); // NaN Reduce, factorials, and BigInt
Because the identity is 1, _.multiply is the perfect callback for an array reduce that computes a running product—the empty-array case naturally yields 1. BigInt input does not work; switch to native * for big integer math.
import multiply from "lodash/multiply";
// Running product via reduce
const factors = [2, 3, 4];
console.log(factors.reduce(multiply, 1)); // 24
// Empty array uses the identity, no special-casing needed
console.log([].reduce(multiply, 1)); // 1
// Factorial of n
function factorial(n) {
return Array.from({ length: n }, (_, i) => i + 1).reduce(multiply, 1);
}
console.log(factorial(5)); // 120
// BigInt: throws
try {
console.log(multiply(2n, 3n));
} catch (err) {
console.log("Threw:", err.message); // "Cannot convert a BigInt value to a number"
}
// Use native * for BigInt instead
console.log(2n * 3n); // 6n 📋 _.multiply vs native *
| Input | _.multiply(a, b) | a * b | Notes |
|---|---|---|---|
6, 4 | 24 | 24 | Same. |
undefined, undefined | 1 | NaN | Lodash returns identity; native gives NaN. |
undefined, 5 | 5 | NaN | Lodash returns the lone operand untouched. |
null, 5 | 0 | 0 | Same: both coerce null to 0. |
"5", 3 | 15 | 15 | Both coerce; * always numerizes. |
0.1, 0.2 | 0.0200…004 | 0.0200…004 | Same float-precision result. |
2n, 3n | throws | 6n | Native * handles BigInt; Lodash does not. |
Pitfalls to avoid
Not a precision fix
_.multiply(0.1, 0.2) still returns 0.020000000000000004. For money, scale to cents first or use a decimal library.
No multiplication happens
_.multiply(undefined, 5) is 5—it returns the lone operand. Don’t assume the result was a real multiplication if either input might be undefined.
Different behaviours
null coerces to 0 → result is 0. undefined short-circuits → result is the other operand. Don’t treat them as interchangeable.
Throws
The factory uses Number() for coercion. Switch to native * if you’re working with BigInts.
Silent NaN
Stringy numbers work ("5" * 3 = 15), but a stray "abc" produces NaN with no error. Validate inputs that come from user forms or untyped JSON.
❓ FAQ
Summary
- Purpose: pairwise multiplication built on
createMathOperation(*, 1); identity1makes it safe insidereduce. - Remember:
undefineddoesn’t multiply (returns lone operand or identity);null→0; stringy numerics coerce; non-numeric strings →NaN; BigInt throws; precision is unfixed. - Next: Lodash _.round() for half-even rounding, or read the official Lodash docs for _.multiply.
_.multiply’s “default for undefined” is 1—not 0. So _.multiply(undefined, undefined) returns 1 (the multiplicative identity), while _.add(undefined, undefined) returns 0. Same factory, different identity element.
6 people found this page helpful
