将数字限制为细分市场的最优雅方式是什么?

Sam*_*lle 109 javascript coding-style

比方说x,ab是数字.我需要x限制段的范围[a, b].

我可以写Math.max(a, Math.min(x, b)),但我不认为这很容易阅读.有没有人有一种聪明的方式以更易读的方式写这个?

Ott*_*ger 178

你这样做是非常标准的.您可以定义一个工具clamp像描述的功能在这里:

/**
 * 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);
};
Run Code Online (Sandbox Code Playgroud)

(虽然扩展语言内置函数通常不受欢迎)

  • 由于各种原因,扩展原生原型(在这种情况下为`Number.prototype`)是不明智的.请参阅https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain中的"不良做法:扩展原生原型" (14认同)
  • JavaScript 本身应该包含很多这样的函数。开发人员不应该因为弥补该语言的不足而受到不满。 (7认同)
  • 如果它不受欢迎,为什么要推荐它......? (5认同)
  • 应该扩展“Math”而不是“Number” (4认同)
  • 不,我是从网站上得到的.只要"Math.min"的参数为"max"且"Math.max"的参数为"min","Math.min"和"Math.max"的嵌套/执行顺序就无关紧要了. (3认同)
  • 开发人员不会因为“弥补语言的不足”而被人皱眉,而是因为以错误或草率的方式做事。扩展原型[是错误的,应该出于各种充分的理由避免](https://softwareengineering.stackexchange.com/a/287853),特别是当正确的方法就像使用函数一样简单时。`const 钳位 = (num, min, max) => Math.min(Math.max(num, min), max)`。 (3认同)

dwe*_*ves 53

一个较少"数学"导向的方法,但也应该工作,这样,</>测试暴露(可能比minimaxing更容易理解)但它实际上取决于你的"可读"是什么意思

function clamp(num, min, max) {
  return num <= min ? min : num >= max ? max : num;
}
Run Code Online (Sandbox Code Playgroud)

  • 它并不快.Math.min/max解决方案是最快的https://jsperf.com/math-clamp/9 (4认同)
  • 最好用这个成语替换<和>与<=和> =,这样就可以减少一次比较.通过这种修正,这绝对是我的首选答案:分钟的最大值令人困惑且容易出错. (3认同)
  • [从Math.random()调用中消除开销,Math.min / max解决方案最快)(https://jsperf.com/math-clamp/14)。此三元解决方案的速度降低了80%。 (3认同)

Tom*_*dym 36

ECMAScript 2017的更新:

Math.clamp(x, lower, upper)
Run Code Online (Sandbox Code Playgroud)

但请注意,截至今天,这是第1阶段提案.在获得广泛支持之前,您可以使用polyfill.

  • 2020 年冬季浏览器仍不可用! (8认同)
  • 如果您想跟踪此提案和其他提案,请参阅:[github.com/tc39/proposals](https://github.com/tc39/proposals) (3认同)
  • 我在tc39 /投标回购中找不到此建议 (2认同)
  • 对于那些寻找的人,该提案作为“数学扩展”列在[第一阶段提案](https://github.com/tc39/proposals/blob/master/stage-1-proposals.md)下。实际提案在这里:https://github.com/rwaldron/proposal-math-extensions (2认同)

CAF*_*FxX 12

Math.clip = function(number, min, max) {
  return Math.max(min, Math.min(number, max));
}
Run Code Online (Sandbox Code Playgroud)

  • 这个解决方案实际上更快,虽然我认为在实际使用该功能时非常优雅地扩展`prototype`。 (2认同)

bin*_*les 8

如果您能够使用 es6 箭头函数,您还可以使用部分应用程序方法:

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
Run Code Online (Sandbox Code Playgroud)

  • 每次想要限制数字时创建一个函数看起来效率很低 (2认同)
  • 可能取决于您的用例。这只是一个工厂函数,用于创建具有设定范围的夹具。您可以创建一次并在整个应用程序中重复使用。不必多次调用。也可能不是适用于不需要锁定设定范围的所有用例的工具。 (2认同)

Ric*_*rdo 7

如果您不想定义任何函数,那么编写它Math.min(Math.max(x, a), b)也不错。

  • 用户@CAFxX(上图)比您早*6*年回答了相同的问题 (3认同)

Nob*_*ita 6

这不是一个"只是使用一个库"的答案,但为了防止您使用Underscore/Lodash,您可以使用.clamp:

_.clamp(yourInput, lowerBound, upperBound);
Run Code Online (Sandbox Code Playgroud)

以便:

_.clamp(22, -10, 10); // => 10
Run Code Online (Sandbox Code Playgroud)

这是它的实现,取自Lodash 来源:

/**
 * 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;
}
Run Code Online (Sandbox Code Playgroud)

此外,值得注意的是Lodash将单个方法作为独立模块提供,因此如果您只需要此方法,则可以在没有其余库的情况下安装它:

npm i --save lodash.clamp
Run Code Online (Sandbox Code Playgroud)

  • 比较“number === number”的目的是什么?它的计算结果肯定总是“true”吗? (4认同)
  • @JivanPal JS 中 `number === number` 为 false 的唯一值是 `NaN`,这是您在编写数字逻辑时通常要处理的情况。`Object.is(number, number)` 始终返回 true。 (2认同)
  • @Rafi,谢谢——与其他语言相比,JavaScript 的特性一直让我感到惊讶。 (2认同)
  • 为什么不只检查 `isNaN` 而不是使用 `===` 哈哈 (2认同)

Mic*_*mel 5

这将三元选项扩展为 if/else,缩小后相当于三元选项,但不牺牲可读性。

const clamp = (value, min, max) => {
  if (value < min) return min;
  if (value > max) return max;
  return value;
}
Run Code Online (Sandbox Code Playgroud)

缩小到 35b(如果使用 则缩小到 43b function):

const clamp=(c,a,l)=>c<a?a:c>l?l:c;
Run Code Online (Sandbox Code Playgroud)

此外,根据您使用的性能工具或浏览器,您会得到基于数学的实现或基于三元的实现是否更快的各种结果。在性能大致相同的情况下,我会选择可读性。