Lodash clamp Lower Bound Greater Than Upper Bound
This article explains the behavior of the _.clamp
function in the Lodash JavaScript library when an inverted range is
passed—specifically when the lower bound is greater than the upper
bound. You will learn the underlying implementation details, why the
function produces an unexpected result rather than throwing an error,
and how to safely handle inverted boundaries in your applications.
The Default Syntax of Lodash _.clamp
Lodash provides _.clamp to restrict a number within an
inclusive lower and upper range:
_.clamp(number, [lower], upper)Under normal usage, passing _.clamp(15, 0, 10) returns
10, and _.clamp(-5, 0, 10) returns
0. However, Lodash does not validate whether
lower <= upper.
What Happens When Lower > Upper
When the lower argument is strictly greater than the
upper argument, _.clamp always returns
the lower boundary, regardless of the input
number.
Consider the following examples:
const _ = require('lodash');
// lower = 10, upper = 5 (lower > upper)
console.log(_.clamp(2, 10, 5)); // Output: 10
console.log(_.clamp(7, 10, 5)); // Output: 10
console.log(_.clamp(12, 10, 5)); // Output: 10Even if the value being clamped is smaller than both bounds, between
both bounds, or larger than both bounds, the result is unconditionally
10.
Why This Happens: The Internal Implementation
The behavior is directly caused by the order of comparison operations
in Lodash's source code. The core logic of _.clamp executes
as follows:
function clamp(number, lower, upper) {
if (upper === undefined) {
upper = lower;
lower = undefined;
}
if (upper !== undefined) {
number = number <= upper ? number : upper;
}
if (lower !== undefined) {
number = number >= lower ? number : lower;
}
return number;
}When evaluated sequentially:
- Upper Bound Check: The function checks
number <= upper. Ifnumberexceedsupper, it is replaced withupper. At this stage,numberis guaranteed to be less than or equal toupper. - Lower Bound Check: The function checks
number >= lower. Becauseloweris greater thanupper, andnumberis already less than or equal toupper,numberis mathematically guaranteed to be strictly less thanlower. - The Final Assignment: The condition
number >= lowerconsistently evaluates tofalse, causing the ternary operator to returnlower.
Because no check exists to swap the arguments or throw an exception, the function silently fails to clamp correctly and resolves to the lower boundary every time.
How to Prevent Errors With Inverted Bounds
If your input ranges are dynamic and might arrive out of order,
normalize them before passing them to _.clamp:
function safeClamp(number, boundA, boundB) {
const min = Math.min(boundA, boundB);
const max = Math.max(boundA, boundB);
return _.clamp(number, min, max);
}
console.log(safeClamp(7, 10, 5)); // Output: 7
console.log(safeClamp(2, 10, 5)); // Output: 5
console.log(safeClamp(12, 10, 5)); // Output: 10Using Math.min and Math.max guarantees that
boundaries are placed in the correct order, avoiding silent logical bugs
in your code.