Diyelim ki x
, a
ve b
sayılardır. x
Segmentin sınırlarına uymam gerekiyor [a, b]
.
Yazabilirim Math.max(a, Math.min(x, b))
ama okumanın çok kolay olduğunu düşünmüyorum. Bunu daha okunaklı bir şekilde yazmanın akıllıca bir yolu olan var mı?
Diyelim ki x
, a
ve b
sayılardır. x
Segmentin sınırlarına uymam gerekiyor [a, b]
.
Yazabilirim Math.max(a, Math.min(x, b))
ama okumanın çok kolay olduğunu düşünmüyorum. Bunu daha okunaklı bir şekilde yazmanın akıllıca bir yolu olan var mı?
Yanıtlar:
Bunu yapma şekliniz oldukça standart. Bir yardımcı program clamp
işlevi tanımlayabilirsiniz :
/**
* 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);
};
(Dil yerleşiklerini genişletmek genellikle hoş karşılanmasa da)
Math.min
ve Math.max
uzun parametre olarak alakasız Math.min
olan max
ve parametresi Math.max
olan min
.
Number.prototype
bu durumda) çeşitli nedenlerden ötürü tavsiye edilmez. En: "yerli prototip Uzatma Kötü örnek" Bkz developer.mozilla.org/en-US/docs/Web/JavaScript/...
daha az "Matematik" odaklı bir yaklaşım, ancak aynı zamanda çalışmalıdır, bu şekilde </> testi teşhir edilir (belki minimum eksiltmeden daha anlaşılabilir), ancak gerçekten "okunabilir" ile ne demek istediğinize bağlıdır
function clamp(num, min, max) {
return num <= min ? min : num >= max ? max : num;
}
Math.random()
aramadan ek yükü kaldırırsanız , bu basit yaklaşım 10 kat daha hızlıdır .
ECMAScript 2017 Güncellemesi:
Math.clamp(x, lower, upper)
Ancak bugün itibariyle bunun bir Aşama 1 önerisi olduğunu unutmayın . Yaygın bir şekilde desteklenene kadar bir çoklu dolgu kullanabilirsiniz .
Bu bir "sadece kitaplık kullan" cevabı olmak istemez, ancak Lodash kullanıyorsanız, şunu kullanabilirsiniz .clamp
:
_.clamp(yourInput, lowerBound, upperBound);
Böylece:
_.clamp(22, -10, 10); // => 10
İşte Lodash kaynağından alınan uygulaması :
/**
* 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;
}
Ayrıca, Lodash'ın tekli yöntemleri bağımsız modüller olarak kullanıma sunduğunu da belirtmek gerekir, bu nedenle yalnızca bu yönteme ihtiyacınız olması durumunda, kütüphanenin geri kalanı olmadan onu kurabilirsiniz:
npm i --save lodash.clamp
Es6 ok işlevlerini kullanabiliyorsanız, kısmi bir uygulama yaklaşımı da kullanabilirsiniz:
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
Ok seksiliği ruhu içinde bir mikro kelepçe / kısıtlama / geçit / & c oluşturabilirsiniz. dinlenme parametrelerini kullanan işlev
var clamp = (...v) => v.sort((a,b) => a-b)[1];
Sonra sadece üç değeri iletin
clamp(100,-3,someVar);
Yani yine, eğer seksiyse, 'kısa' demek istiyorsun
clamp
, perf için sıralama , karmaşık mantığınız varsa ("seksi" olsa bile) ciddi bir darbe alacaktır
Bu, üçlü seçeneği, üçlü seçeneğe eşdeğer olan ancak okunabilirlikten ödün vermeyen if / else şeklinde genişletir.
const clamp = (value, min, max) => {
if (value < min) return min;
if (value > max) return max;
return value;
}
35b'ye kadar minifiler (veya kullanılıyorsa 43b function
):
const clamp=(c,a,l)=>c<a?a:c>l?l:c;
Ayrıca, kullandığınız mükemmel araç veya tarayıcıya bağlı olarak, Matematik tabanlı uygulamanın mı yoksa üçlü tabanlı uygulamanın mı daha hızlı olduğu konusunda çeşitli sonuçlar elde edersiniz. Aşağı yukarı aynı performans durumunda, okunabilirliği tercih ederim.
Benim favorim:
[min,x,max].sort()[1]
[1,5,19].sort()[1]
19 döndürür. Şu şekilde düzeltilebilir: [min,x,max].sort(function(a, b) { return a - b; })[1]
ama bu artık seksi değil. Ayrıca yoğun şekilde kullanıldığında, sadece üç sayıyı karşılaştırmak için yeni bir dizi oluşturmak bir performans sorunu olabilir.
[min, x, max].sort((a,b) => a-b)[1]