GreatFrontEnd 풀이 - Clamp

Clamp

clamp 함수는 특정 숫자(value)를 최소값(min)과 최대값(max) 사이로 제한하는 함수입니다.

JavaScript에서 clamp 함수를 두 가지 방식으로 구현해보았습니다.

 

첫 번째는 조건문으로 value를 lower, upper와 비교해 적절한 값을 반환하는 방법입니다.

 

/**
 * @param {number} value The number to clamp.
 * @param {number} lower The lower bound.
 * @param {number} upper The upper bound.
 * @returns {number} Returns the clamped number.
 */
export default function clamp(value, lower, upper) {
  if (value <= lower) {
    return lower;
  }
  if (value >= upper) {
    return upper;
  }

  return value;
}

 

두 번째는 JavaScript의 Math 객체의 min, max 메서드를 사용하는 방법입니다.

 

 

/**
 * @param {number} value The number to clamp.
 * @param {number} lower The lower bound.
 * @param {number} upper The upper bound.
 * @returns {number} Returns the clamped number.
 */
export default function clamp(value, lower, upper) {
  return Math.min(Math.max(value, lower), upper)
}

 

최신 JavaScript 엔진 기준으로 두 방식의 성능 차이는 거의 없다고 알려져 있습니다.

 


 

찾아보니 CSS에서도 비슷한 역할을 하는 clamp 함수를 반응형을 위해 지원하고 있습니다.

CSS의 clamp()는 최소값, 이상적인 값, 최대값을 한 번에 정의해 반응형 레이아웃을 구현할 수 있습니다.

 

clamp(min, preferred, max)

 

예를 들어 반응형 폰트 크기는 아래처럼 표현할 수 있습니다.

 

font-size: clamp(1rem, 2.5vw, 2rem);

 

  • 화면이 작아도 1rem보다 작아지지 않고
  • 화면이 커져도 2rem을 넘지 않으며
  • 그 사이에서는 2.5vw 기준으로 자연스럽게 변화합니다.

 

미디어 쿼리 없이도 부드러운 반응형 레이아웃을 만들 수 있다는 점에서 자주 사용됩니다.

 

https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/clamp

 

clamp() - CSS | MDN

font-size: clamp(1rem, 2.5vw, 2rem); font-size: clamp(1.5rem, 2.5vw, 4rem); font-size: clamp(1rem, 10vw, 2rem); The font-size of this text varies depending on the base font of the page, and the size of the viewport. Note that using clamp() for font sizes,

developer.mozilla.org

 


 

Lodash 라이브러리에서 clamp 함수를 지원하고 있어요.

 

내부 구현을 보면 baseClamp라는 함수를 따로 두고, 입력값 검증과 보정을 수행한 뒤 이를 재사용하는 구조입니다.

lower, upper가 없는 경우나 숫자가 아닌 값이 들어오는 케이스까지 고려하고 있습니다.

 

baseClamp

    /**
     * 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;
    }

 

 

  • number === number 비교를 통해 NaN을 걸러냄
  • lower, upper가 undefined인 경우도 허용
  • 단순 clamp 로직만 담당하는 순수한 내부 구현

 

 

clamp

/**
     * Clamps `number` within the inclusive `lower` and `upper` bounds.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Number
     * @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.
     * @example
     *
     * _.clamp(-10, -5, 5);
     * // => -5
     *
     * _.clamp(10, -5, 5);
     * // => 5
     */
    function clamp(number, lower, upper) {
      if (upper === undefined) {
        upper = lower;
        lower = undefined;
      }
      if (upper !== undefined) {
        upper = toNumber(upper);
        upper = upper === upper ? upper : 0;
      }
      if (lower !== undefined) {
        lower = toNumber(lower);
        lower = lower === lower ? lower : 0;
      }
      return baseClamp(toNumber(number), lower, upper);
    }

 

 

  • 인자 개수가 2개인 경우도 처리
  • 숫자 타입 변환 및 NaN 보정
  • 실무에서 발생할 수 있는 엣지 케이스를 폭넓게 고려한 구현

 

 

https://github.com/lodash/lodash/blob/4.17.15/lodash.js#L13981

 

lodash/lodash.js at 4.17.15 · lodash/lodash

A modern JavaScript utility library delivering modularity, performance, & extras. - lodash/lodash

github.com

 

간단한 함수지만, 실무에서는 자주 사용되기 때문에 한 번쯤 구현과 사용 사례를 정리해두면 좋은 함수라고 생각합니다!

 


 

첫 문제 풀이라 자세하게 작성해봤어요 😁