본문 바로가기
Javascript/Basics

Math.min( ...args )함수에서 문자열 타입을 인자로 사용할 수 있을까?

by seunghyeok lee 2023. 8. 16.

상황

Math.min("115", "12") // 12 입력값에 문자열이 들어간 상황

mdn 문서에서는 Math.min(...args) 함수에서 매개변수는 숫자의 타입만 설명하고 있습니다.

Parameters value1, …, valueN Zero or more numbers among which the lowest value will be selected and returned.

Math.min() 정적 메서드는 입력 매개변수로 주어진 숫자 중 가장 작은 숫자를 반환하거나 매개변수가 없는 경우 무한대를 반환합니다.

MDN에서 말하는 주어진 숫자라는 표현에서 문자열이 들어갈 수 있어서 가장 작은 숫자의 의미를 말그대로 리터럴의 가장 작은 숫자인지 아니면 문자열이 유니코드로 변환해서 각 코드끼리 비교해서 가장 작은 것을 이야기하는지 알아봐야 했습니다.

아래는 Ecma-262 문서는 다음과 같습니다.

21.3.2.25 Math.min ( ...args )

Given zero or more arguments, this function calls ToNumber on each of the arguments and returns the smallest of the resulting values.

It performs the following steps when called:

  1. Let coerced be a new empty List.
  2. For each element arg of args, do
    a. Let n be ? ToNumber_(arg).
    _b. Append n to coerced.
  3. Let lowest be +∞𝔽.
  4. For each element number of coerced, do
    a. If number is NaN, return NaN.
    b. If number is -0𝔽 and lowest is +0𝔽, set lowest to -0𝔽.
    c. If number < lowest, set lowest to number.
  5. Return lowest.

여기서 우리가 확인해야 하는 것은 ToNumber(arg) 추상연산자입니다. 왜냐하면 문서에서 Math.min(...args)는 각 인자들의 값들을 ToNumber(args)함수를 호출하고 있습니다.

7.1.4 ToNumber ( argument )

The abstract operation ToNumber takes argument argument (an ECMAScript language value) and returns either a normal completion containing a Number or a throw completion. It converts argument to a value of type Number. It performs the following steps when called:

  1. If argument is a Number, return argument.
  2. If argument is either a Symbol or a BigInt, throw a TypeError exception.
  3. If argument is undefined, return NaN.
  4. If argument is either null or false, return +0𝔽.
  5. If argument is true, return 1𝔽.
  6. If argument is a String, return StringToNumber(argument).
  7. Assert: argument is an Object.
  8. Let primValue be ? ToPrimitive(argument, number).
  9. Assert: primValue is not an Object.
  10. Return ? ToNumber(primValue).

ToNumber(argument) 추상 연산자는 각 인자들을 최대한 숫자 타입으로 변형합니다.

여기서 1-7번 단계까지는 원시 타입을 숫자 타입으로 변형하는 단계이며 나머지 단계는 객체 타입을 원시값으로 변환 한 다음 해당 원시 값을 숫자 타입으로 변환하는 과정입니다. 우리가 확인하는 것은 인자가 string 타입이므로 7번 단계에 해당합니다. 즉 인자는 StringToNumber(argument) 추상연산자를 반환합니다.

StringToNumber(argument)는 메서드명처럼 string 타입을 number 타입으로 변환합니다.

7.1.4.1.1 StringToNumber ( str )

The abstract operation StringToNumber takes argument str (a String) and returns a Number. It performs the following steps when called:

  1. Let text be StringToCodePoints(str).
  2. Let literal be ParseText(text, StringNumericLiteral).
  3. If literal is a List of errors, return NaN.
  4. Return StringNumericValue of literal.

이 메서드는 우리가 평소에 js에서 문자를 숫자로 변환할 때 동작하는 원리입니다. 간단하게 요약한다면 주어진 문자열을 코드 포인트의 목록으로 변환한 후, 해당 목록을 구문 분석하여 숫자 리터럴을 식별하고, 그 리터럴의 문자열 표현을 실제 숫자 값으로 변환하는 과정을 거칩니다. 만약 문자열이 유효한 숫자 형식이 아니라면 NaN을 반환합니다.

이렇게 우리는 각 단계별로 호출하는 메서드를 살펴보았습니다.

정리하자면 Math.min(...args)에 args 중 인자가 문자열이면 ToNumber(argument) 연산자를 통해 n에 NaN 혹은 숫자의 타입을 가진 number를 반환합니다.

a. Let n be ? ToNumber(arg).

그리고 비교를 하는 과정은 다음과 같습니다.

  1. Let lowest be +∞𝔽.
  2. For each element number of coerced, do
    a. If number is NaN, return NaN.
    b. If number is -0𝔽 and lowest is +0𝔽, set lowest to -0𝔽.Return lowest.
    c. If number < lowest, set lowest to number.

여기서 coerced는 NaN 혹은 문자열만 있으니 다음과 같습니다.

만약 coerced 리스트의 요소에 하나라도 NaN이 있으면 Math.min(...args) 함수는 NaN을 반환합니다.

NaN이 없다면 단순 수학 비교(number < lowest)를 통해 가장 작은 값을 반환합니다.

IsLessThan ( x, y, LeftFirst ) 알고리즘 사용

정리

Math.min(...args)는 args의 각 인자들을 최대한 number 타입으로 변환하여 변환할 수 없는 타입은 NaN으로 변환하여 NaN을 반환하거나 인자들이 유효한 number 타입일 경우에는 isLessThan 알고리즘을 사용하여 가장 작은 숫자를 반환합니다. 마지막으로 인자들을 제공하지 않는 경우(빈 상태) lowest에 양의 무한대로 초기화되므로 Infinity를 반환합니다.

댓글