213

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?

1
  • no this is best
    – stoic_monk
    Commented Jan 6 at 4:44

10 Answers 10

257

The way you do it is pretty standard. You can define a utility clamp function:

/**
 * Returns a number whose value is limited to the given range.
 *
 * Example: limit the output of this computation to between 0 and 255
 * (x * 255).clamp(0, 255)
 *
 * @param {Number} min The lower boundary of the output range
 * @param {Number} max The upper boundary of the output range
 * @returns A number in the range [min, max]
 * @type Number
 */
Number.prototype.clamp = function(min, max) {
  return Math.min(Math.max(this, min), max);
};

(Although extending language built-ins is generally frowned upon)

3
  • 67
    Extending native prototypes (Number.prototype in this case) is ill-advised for a variety of reasons. See "Bad practice: Extension of native prototypes" at developer.mozilla.org/en-US/docs/Web/JavaScript/…
    – broofa
    Commented May 9, 2018 at 20:08
  • 8
    Developers are not frowned upon for "picking up the slack of the language", but for doing it in a wrong or sloppy way. Extending prototypes is wrong and should be avoided for a variety of good reasons, especially when the right way is as easy as using a function. const clamp = (num, min, max) => Math.min(Math.max(num, min), max).
    – Aurelio
    Commented Feb 12, 2021 at 15:03
  • 13
    Should have extended Math and not Number
    – vsync
    Commented Mar 4, 2021 at 16:25
93

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
}
8
  • 6
    Better to replace < and > with <= and >= in this idiom, so that there's potentially one less comparison done. With that correction, this is definitely my preferred answer: maxes of mins are confusing and error prone.
    – Don Hatch
    Commented Jul 13, 2016 at 22:21
  • 8
    It's not faster. Math.min/max solution is fastest jsperf.com/math-clamp/9 Commented Feb 20, 2017 at 20:17
  • 1
    @ManuelDiIorio huh? under current version of Chrome, the simple ternary is twice as fast as Math.min/max - and if you remove the overhead from the far more expensive Math.random() call, this simple approach is 10 x faster. Commented Oct 5, 2017 at 8:48
  • This has unexpected behavior in the accidental scenario of the arguments being min > max
    – Thomas An
    Commented Nov 2, 2017 at 17:34
  • 6
    Removing the overhead from Math.random() call, Math.min/max solution is fastest. This ternary solution is 80% slower.
    – idbrii
    Commented Dec 17, 2018 at 18:27
79

There's a proposal to add an addition to the built-in Math object to do this:

Math.clamp(x, lower, upper)

But note that as of today, it's a Stage 1 proposal. Until it gets widely supported (which is not guaranteed), you can use a polyfill.

8
70

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)

3
  • 2
    This solution is actually way faster, although I consider extending the prototype very elegant when it comes to actually use the function.
    – MaxArt
    Commented Jul 10, 2012 at 9:10
  • 1
    This is an answer from 2012, so seeing the implementation extending prototype is somewhat understandable, BUT it has to be noted it's now widely considered a bad practice. The Math.max(min, Math.min(number, max)) (the relevant bit) is still valid and worth an upvote, so @CAFxX would you consider editing the answer and avoiding the prototype mutation? I think some upvotes you would get are diverted to this answer
    – Aurelio
    Commented Feb 12, 2021 at 14:58
  • Personally I prefer that, so values follow each other: Math.min(Math.max(MIN, VALUE), MAX), and it's easier to remember: min+max functions, and min value max arguments. Commented Aug 27, 2023 at 14:24
19

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
7
  • 8
    What is the purpose of the comparison number === number? Surely it always evaluates to true?
    – Jivan Pal
    Commented Sep 13, 2020 at 13:08
  • 7
    @JivanPal the only value in JS where number === number is false is NaN, and that is a case you usually want to handle when writing number logic. Object.is(number, number) always returns true.
    – Rafi
    Commented Dec 20, 2020 at 8:39
  • 2
    @Rafi, thanks — JavaScript never ceases to amaze me with its idiosyncrasies compared to other languages.
    – Jivan Pal
    Commented Dec 21, 2020 at 15:33
  • 2
    Why not just check isNaN instead of using === lol
    – Justin
    Commented Feb 10, 2023 at 2:45
  • 1
    Value to value comparison allows to detect NaN in multiple programming languages without any performance cost. Commented Apr 23, 2023 at 3:04
10

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
3
  • 2
    Creation of a function every time you want to clamp a number looks very inefficient
    – George
    Commented Apr 20, 2020 at 14:04
  • 2
    Probably depends on your use case. This is just a factory function to create the clamp with a set range. You could create once and reuse throughout your app whatever. doesn't have to be called multiple times. Also may not be the tool for all use cases where you don't need to lock in a set range.
    – bingles
    Commented Apr 20, 2020 at 18:11
  • 1
    @George if you doesn't need to keep the range, just remove the inner arrow function and move the value parameter to the outer arrow function
    – Alynva
    Commented May 8, 2020 at 17:16
6

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

1
  • 7
    User @CAFxX (above) answered the same 6 years before you
    – vsync
    Commented Jan 19, 2021 at 16:29
5

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.

1

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'

1
  • 3
    you shouldn't use arrays and sorting for a clamp, perf will take a serious hit if you have complex logic (even if it is "sexy") Commented Nov 12, 2019 at 18:22
-8

My favorite:

[min,x,max].sort()[1]
7
  • 21
    Downvoting because it doesn't work. [1,5,19].sort()[1] returns 19. It could be fixed like this: [min,x,max].sort(function(a, b) { return a - b; })[1] but this isn't sexy anymore. Beside when heavily used it may be a performance issue to create a new array just to compare three numbers.
    – kayahr
    Commented Mar 14, 2016 at 15:50
  • 3
    IMHO this is far more readable than any of the other options, especially with arrow functions: [min, x, max].sort((a,b) => a-b)[1]
    – zaius
    Commented Jul 28, 2016 at 17:27
  • 7
    The reason why this doesn't always work is because the sort method does not compare numerical values properly. (It treats them like strings) Commented May 2, 2018 at 4:05
  • @JohnLeuenhagen the what now?!? Commented Apr 30, 2021 at 20:27
  • 1
    @SreenikethanI yeah, unfortunately, JavaScript has quite a few nasty "gotchas" like this. JavaScript programmers just have to know about them and work around them. Commented May 2, 2021 at 8:02

Not the answer you're looking for? Browse other questions tagged or ask your own question.