Today, we’re going to dive into one of JavaScript’s coolest features: prototypes. A prototype lets us add a method that becomes available to every value of a given type. In this example, we will teach every number how to map itself from one range to another and constrain itself between a minimum and maximum value.

That means we can write a chain such as (123).map(...).constrain(...). The syntax reads from left to right, with each number carrying the new methods through JavaScript’s prototype chain.

Mapping One Set of Numbers to Another

The first function maps a number from one range to another. We add it to Number.prototype, which is where JavaScript looks for a method when it is not found directly on a number.

Number.prototype.map = function (inMin, inMax, outMin, outMax) {
  if (inMin === inMax) throw new RangeError("input bounds must differ");
  return ((this - inMin) * (outMax - outMin)) / (inMax - inMin) + outMin;
};

Inside the method, this is the number on the left side of .map(). JavaScript finds map through Number.prototype, calls it with that number as this, and returns the mapped value. For example:

(123).map(0, 500, 0, 100); // 24.6

The check for equal input bounds avoids dividing by zero. The function maps values outside the input range too; it does not clamp them automatically.

Constrain a Number Between Minimum and Maximum

The second function constrains a number between a minimum and maximum value. We can teach numbers this method in exactly the same way:

Number.prototype.constrain = function (min, max) {
  return Math.min(max, Math.max(min, this));
};

Any number below the minimum becomes the minimum, and any number above the maximum becomes the maximum. A number already inside the range stays unchanged.

Combining the Map and Constrain Methods

Now we can map a number from one range to another and constrain the result in one readable chain:

(123).map(0, 500, 0, 100).constrain(0, 100); // 24.6

Here, map turns 123 from the 0 to 500 range into 24.6 in the 0 to 100 range. Because map returns another number, JavaScript can find constrain on Number.prototype and immediately call it. If the mapped result falls outside 0 to 100, constrain pulls it back inside the range.

This is what made the prototype approach so interesting to me: two general calculations become fluent methods that can be used on any number.

Pros and Cons of Extending Number.prototype

Adding methods to the prototype has some real advantages:

  • The chained form is compact and readable.
  • The method is available to every number without wrapping it in a custom class.
  • It provides a small, practical demonstration of prototype lookup and this.

There are tradeoffs too. Changing a built-in prototype affects the whole JavaScript environment. Another library, or a future JavaScript standard, could add a method with the same name. A direct assignment also creates an enumerable property, which can surprise code that inspects the prototype. For a personal experiment or a controlled program, this is a neat way to learn how JavaScript works. For shared libraries and larger applications, standalone functions are usually safer.

The Standalone Function Method

The same behavior can be written without changing Number.prototype:

function mapRange(value, inMin, inMax, outMin, outMax) {
  if (inMin === inMax) throw new RangeError("input bounds must differ");
  return ((value - inMin) * (outMax - outMin)) / (inMax - inMin) + outMin;
}

function constrain(value, min, max) {
  return Math.min(max, Math.max(min, value));
}

constrain(mapRange(123, 0, 500, 0, 100), 0, 100); // 24.6

This form is easier to import, test, and reuse without changing numbers globally. It is the safer default for production code, but it hides the prototype mechanism that this article set out to teach.

The prototype version remains the star of this example because it shows something distinctive about JavaScript: behavior can be shared through the prototype chain, turning an ordinary number into the starting point of a readable calculation. For more detail, see MDN’s guide to inheritance and the prototype chain.



Buy Me a Coffee