什么是最优雅的方式来限制一个数字的片段?

假设 xab是数字,我需要将 x限制在段 [a, b]的边界内。

换句话说,我需要一个 钳子功能:

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

有人能想出一个更易读的版本吗?

169169 次浏览

你可以定义一个实用的 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);
};

(尽管扩展内置语言通常是不受欢迎的)

一个简单的方法就是

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

很明显,你可以定义一个函数来包装这个:

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

最初,这个答案还将上面的函数添加到全局 Math对象中,但那是过去时代的遗物,所以已经被删除了(感谢@Aurelio 的建议)

一个较少“数学”导向的方法,但也应该工作,这样,</>测试是公开的(可能比最小化更容易理解) ,但它真的取决于你的意思是“可读”

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

我的最爱:

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

有人建议在内置的 Math对象中添加一个附件来实现这一点:

Math.clamp(x, lower, upper)

但请注意,到今天为止,这是阶段1 建议书。在它得到广泛支持之前(这是不能保证的) ,您可以使用 填料

这并不是一个“只需使用一个库”的答案,但是为了以防万一你正在使用 Lodash,你可以使用 .clamp:

_.clamp(yourInput, lowerBound, upperBound);

因此:

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

以下是它的实现,摘自 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;
}

另外,值得注意的是,Lodash 将单个方法作为独立模块提供,所以如果您只需要这个方法,您可以不使用库的其他部分安装它:

npm i --save lodash.clamp

在箭性感的精神,你可以创建一个微型 使用静止参数实现钳位/约束/闸位/等功能

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

然后传入三个值

clamp(100,-3,someVar);

也就是说,如果你说的性感是指“矮”的话

如果您能够使用 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;

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