[javascript] What's the most elegant way to cap a number to a segment?

Let's say x, a and b are numbers. I need to limit x to the bounds of the segment [a, b].

In other words, I need a clamp function:

clamp(x) = max( a, min(x, b) )

Can anybody come up with a more readable version of this?

This question is related to javascript clamp

The answer is


If you are able to use es6 arrow functions, you could also use a partial application approach:

const clamp = (min, max) => (value) =>
    value < min ? min : value > max ? max : value;

clamp(2, 9)(8); // 8
clamp(2, 9)(1); // 2
clamp(2, 9)(10); // 9

or

const clamp2to9 = clamp(2, 9);
clamp2to9(8); // 8
clamp2to9(1); // 2
clamp2to9(10); // 9

a less "Math" oriented approach ,but should also work , this way, the < / > test is exposed (maybe more understandable than minimaxing) but it really depends on what you mean by "readable"

function clamp(num, min, max) {
  return num <= min ? min : num >= max ? max : num;
}

Update for ECMAScript 2017:

Math.clamp(x, lower, upper)

But note that as of today, it's a Stage 1 proposal. Until it gets widely supported, you can use a polyfill.


This does not want to be a "just-use-a-library" answer but just in case you're using Lodash you can use .clamp:

_.clamp(yourInput, lowerBound, upperBound);

So that:

_.clamp(22, -10, 10); // => 10

Here is its implementation, taken from Lodash source:

/**
 * The base implementation of `_.clamp` which doesn't coerce arguments.
 *
 * @private
 * @param {number} number The number to clamp.
 * @param {number} [lower] The lower bound.
 * @param {number} upper The upper bound.
 * @returns {number} Returns the clamped number.
 */
function baseClamp(number, lower, upper) {
  if (number === number) {
    if (upper !== undefined) {
      number = number <= upper ? number : upper;
    }
    if (lower !== undefined) {
      number = number >= lower ? number : lower;
    }
  }
  return number;
}

Also, it's worth noting that Lodash makes single methods available as standalone modules, so in case you need only this method, you can install it without the rest of the library:

npm i --save lodash.clamp

A simple way would be to use

Math.max(min, Math.min(number, max));

and you can obviously define a function that wraps this:

function clamp(number, min, max) {
  return Math.max(min, Math.min(number, max));
}

Originally this answer also added the function above to the global Math object, but that's a relic from a bygone era so it has been removed (thanks @Aurelio for the suggestion)


This expands the ternary option into if/else which minified is equivalent to the ternary option but doesn't sacrifice readability.

const clamp = (value, min, max) => {
  if (value < min) return min;
  if (value > max) return max;
  return value;
}

Minifies to 35b (or 43b if using function):

const clamp=(c,a,l)=>c<a?a:c>l?l:c;

Also, depending on what perf tooling or browser you use you get various outcomes of whether the Math based implementation or ternary based implementation is faster. In the case of roughly the same performance, I would opt for readability.


In the spirit of arrow sexiness, you could create a micro clamp/constrain/gate/&c. function using rest parameters

var clamp = (...v) => v.sort((a,b) => a-b)[1];

Then just pass in three values

clamp(100,-3,someVar);

That is, again, if by sexy, you mean 'short'


My favorite:

[min,x,max].sort()[1]

If you don’t want to define any function, writing it like Math.min(Math.max(x, a), b) isn’t that bad.