สมมติว่าx
, a
และb
ตัวเลข ฉันจำเป็นต้องหมวกขอบเขตของส่วนx
[a, b]
ฉันเขียนMath.max(a, Math.min(x, b))
ได้ แต่ไม่คิดว่าจะอ่านง่ายขนาดนี้ ใครมีวิธีที่ชาญฉลาดในการเขียนสิ่งนี้ด้วยวิธีที่อ่านง่ายกว่านี้?
สมมติว่าx
, a
และb
ตัวเลข ฉันจำเป็นต้องหมวกขอบเขตของส่วนx
[a, b]
ฉันเขียนMath.max(a, Math.min(x, b))
ได้ แต่ไม่คิดว่าจะอ่านง่ายขนาดนี้ ใครมีวิธีที่ชาญฉลาดในการเขียนสิ่งนี้ด้วยวิธีที่อ่านง่ายกว่านี้?
คำตอบ:
วิธีที่คุณทำนั้นค่อนข้างได้มาตรฐาน คุณสามารถกำหนด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.min
และMath.max
ไม่เกี่ยวข้องตราบเท่าที่พารามิเตอร์ของMath.min
เป็นmax
และพารามิเตอร์ของมีMath.max
min
Number.prototype
ในกรณีนี้) ไม่ได้รับคำแนะนำจากหลายสาเหตุ ดู "แนวทางปฏิบัติที่ไม่ดี: ส่วนขยายของต้นแบบดั้งเดิม" ที่developer.mozilla.org/en-US/docs/Web/JavaScript/…
วิธีที่เน้น "คณิตศาสตร์" น้อยลง แต่ก็ควรได้ผลเช่นกันด้วยวิธีนี้การทดสอบ </> จะถูกเปิดเผย (อาจเข้าใจได้มากกว่าการย่อขนาด) แต่จริงๆแล้วขึ้นอยู่กับความหมายของคุณโดย "อ่านได้"
function clamp(num, min, max) {
return num <= min ? min : num >= max ? max : num;
}
Math.random()
การโทรวิธีการง่ายๆที่นี้คือ10 x เร็วขึ้น
อัปเดตสำหรับ ECMAScript 2017:
Math.clamp(x, lower, upper)
แต่ทราบว่า ณ วันนี้ก็เป็นขั้นตอนที่ 1 ข้อเสนอ จนกว่าจะได้รับการสนับสนุนอย่างกว้างขวางคุณสามารถใช้polyfill
Math.clip = function(number, min, max) {
return Math.max(min, Math.min(number, max));
}
prototype
ความสง่างามมากเมื่อต้องใช้ฟังก์ชันนี้จริงๆ
สิ่งนี้ไม่ได้ต้องการเป็นคำตอบ "just-use-a-library" แต่ในกรณีที่คุณใช้ 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
หากคุณสามารถใช้ฟังก์ชันลูกศร 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)
ก็ไม่เลว
ด้วยจิตวิญญาณแห่งความเซ็กซี่ของลูกศรคุณสามารถสร้างที่หนีบขนาดเล็ก / ข้อ จำกัด / ประตู / & c ฟังก์ชันโดยใช้พารามิเตอร์ส่วนที่เหลือ
var clamp = (...v) => v.sort((a,b) => a-b)[1];
จากนั้นส่งผ่านสามค่า
clamp(100,-3,someVar);
นั่นคืออีกครั้งถ้าโดยเซ็กซี่คุณหมายถึง 'สั้น'
clamp
perf จะได้รับความนิยมอย่างมากหากคุณมีตรรกะที่ซับซ้อน (แม้ว่ามันจะ "เซ็กซี่"
สิ่งนี้จะขยายอ็อพชัน ternary เป็น if / else ซึ่ง minified นั้นเทียบเท่ากับอ็อพชัน ternary แต่ไม่ลดทอนความสามารถในการอ่าน
const clamp = (value, min, max) => {
if (value < min) return min;
if (value > max) return max;
return value;
}
ลดขนาดเป็น 35b (หรือ 43b ถ้าใช้function
):
const clamp=(c,a,l)=>c<a?a:c>l?l:c;
นอกจากนี้ขึ้นอยู่กับว่าคุณใช้เครื่องมือหรือเบราว์เซอร์ที่สมบูรณ์แบบใดคุณจะได้ผลลัพธ์ที่หลากหลายว่าการใช้งานตามคณิตศาสตร์หรือการใช้งานตามหลักสามนั้นเร็วกว่า ในกรณีที่มีประสิทธิภาพใกล้เคียงกันฉันจะเลือกให้อ่านง่าย
ของโปรด:
[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]