【发布时间】:2012-07-09 17:27:52
【问题描述】:
假设x、a 和b 是数字。我需要将x 限制在[a, b] 段的范围内。
换句话说,我需要一个clamp function:
clamp(x) = max( a, min(x, b) )
谁能想出一个更易读的版本?
【问题讨论】:
标签: javascript clamp
假设x、a 和b 是数字。我需要将x 限制在[a, b] 段的范围内。
换句话说,我需要一个clamp function:
clamp(x) = max( a, min(x, b) )
谁能想出一个更易读的版本?
【问题讨论】:
标签: javascript clamp
你做这件事的方式很标准。你可以定义一个实用程序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);
};
(虽然扩展语言内置插件通常不受欢迎)
【讨论】:
Number.prototype)是不明智的,原因有很多。请参阅developer.mozilla.org/en-US/docs/Web/JavaScript/… 上的“不良做法:扩展原生原型”
const clamp = (num, min, max) => Math.min(Math.max(num, min), max).
Math 而不是 Number
一种较少“数学”导向的方法,但也应该有效,这样,< / > 测试就暴露出来了(可能比最小化更容易理解),但这真的取决于你所说的“可读”是什么意思
function clamp(num, min, max) {
return num <= min
? min
: num >= max
? max
: num
}
【讨论】:
Math.random() 调用中移除开销,这个简单的方法是 10 x faster。
【讨论】:
一个简单的方法是使用
Math.max(min, Math.min(number, max));
你显然可以定义一个包装这个的函数:
function clamp(number, min, max) {
return Math.max(min, Math.min(number, max));
}
最初这个答案也将上述函数添加到全局 Math 对象中,但这是过去时代的遗物,因此已被删除(感谢 @Aurelio 的建议)
【讨论】:
prototype 非常优雅。
Math.max(min, Math.min(number, max))(相关位)仍然有效并且值得一票,所以@CAFxX 你会考虑编辑答案并避免原型突变吗?我认为你会得到一些赞成票被转移到this answer
这不想成为“仅使用库”的答案,但以防万一您使用 Lodash,您可以使用 .clamp:
_.clamp(yourInput, lowerBound, upperBound);
这样:
_.clamp(22, -10, 10); // => 10
这是它的实现,取自 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;
}
此外,值得注意的是,Lodash 将单个方法作为独立模块提供,因此如果您只需要此方法,则可以在没有库的其余部分的情况下安装它:
npm i --save lodash.clamp
【讨论】:
number === number的目的是什么?当然它总是评估为true?
number === number 为假的唯一值是NaN,这是您在编写数字逻辑时通常想要处理的情况。 Object.is(number, number) 总是返回 true。
如果你能够使用 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
【讨论】:
如果你不想定义任何函数,写成Math.min(Math.max(x, a), b) 也不错。
【讨论】:
这将三元选项扩展为 if/else,它缩小相当于三元选项,但不会牺牲可读性。
const clamp = (value, min, max) => {
if (value < min) return min;
if (value > max) return max;
return value;
}
缩小到 35b(如果使用 function,则缩小到 43b):
const clamp=(c,a,l)=>c<a?a:c>l?l:c;
此外,根据您使用的性能工具或浏览器,您会获得基于数学的实现还是基于三元的实现更快的各种结果。在性能大致相同的情况下,我会选择可读性。
【讨论】:
本着箭头性感的精神,你可以创造一个微 钳位/约束/门/&c。使用剩余参数的函数
var clamp = (...v) => v.sort((a,b) => a-b)[1];
然后传入三个值
clamp(100,-3,someVar);
同样,如果说性感,你的意思是“短”
【讨论】:
clamp使用数组和排序,如果你有复杂的逻辑(即使它很“性感”),性能会受到严重打击
我最喜欢的:
[min,x,max].sort()[1]
【讨论】:
[1,5,19].sort()[1] 返回 19。可以这样修复:[min,x,max].sort(function(a, b) { return a - b; })[1] 但这不再性感了。除此之外,在大量使用时,创建一个新数组只是为了比较三个数字可能是一个性能问题。
[min, x, max].sort((a,b) => a-b)[1]