[Javascript] parseInt("0x")의 결과는 0이 아니다?

2022. 2. 11. 15:18Frontend/JS

이전까지 parseInt() 함수의 기능은,  숫자로 시작하는 문자열(ex: "1xyz") 을 정수 타입으로 변경해주는 정도로만 알고있었습니다. 아예 틀린 말은 아니지만, 그렇다고 정확하게 이해한 답변은 아닙니다.

 

코드로 확인해보겠습니다.

parseInt("2x")
>>> 2

예상대로 2 가 출력됩니다.

 

그럼 "1x" 는 어떨까요?

parseInt("1x")
>>> 1

역시 예상한 숫자 1이 출력됩니다.

 

마지막으로 "0x"까지 해보겠습니다.

NaN,,? Not a Number 요..?

왜 이런 결과가 나오는지, parseInt() 의 정확한 정의부터 활용, 주의해야할 점 까지 글로 풀어보겠습니다.

 


parseInt()

MDN web docs 에는 parseInt() 함수에 대해 아래처럼 정의합니다.

parseInt()
parseInt() 함수는 문자열 인자를 파싱하여 특정 진수(수의 진법 체계에서 기준이 되는 값)의 정수로 반환합니다.

즉 숫자로 시작하는 인자를 문자열을 정수타입으로 반환 한다는 표현보단, "문자열을 파싱하여 특정 진수의 정수로 변환" 이 더 명확한 의미입니다.

 

parseInt() 함수의 첫번째 인자인 string문자열 형태로 받으며, 두번째 인자 radix옵션 값으로 숫자 타입을 받습니다.

 

parseInt() 예시

아래 예시에서는 parseInt() 의 첫번째 인자만 사용했습니다. 

parseInt('10')
>>> 10

parseInt("10xxx")
>>> 10

parseInt("10xxx10")
>>> 10

parseInt("xxx10xxx10")
>>> NaN

그럼 왜 parseInt() 의 두번째 인자까지 명시해주어야하는지 알아보겠습니다.

 

 

parseInt() 의 두번째 인자 radix

parseInt()의 첫번째 인자인 string 은 두번째 인자(n)에 따라 n진법으로 파싱됩니다.

두번째 인자인 radix 는 string의 진수를 나타냅니다. (범위 2 ~ 36 의 정수)

즉 radix 값이 무엇이냐에 따라 string 의 값이 변합니다.

 

radix 가 10이라면 string 을 10진수로 파싱해주고, 2 일 땐 2진수로 string 을 파싱합니다.

parseInt("10", 2)
>>> 2

여기서 흥미로운 점을 발견했는데, 아래 코드를 확인해 보겠습니다.

parseInt("210", 2)

위 코드에선 어떤 결과가 출력될까요 ? 210 이란 숫자를 이진수로 만들까요? 결과는 NaN 이 나옵니다.

이진수는 숫자 0과 1로 이루어진 숫자를 의미하기 때문에 숫자 2 를 파싱할 수 없어 NaN이 결과로 나옵니다.

 

 

n진법에 따른 파싱 결과 

진법은 수를 셀 때, 자릿수가 올라가는 단위를 기준으로 하는 셈법의 총칭이다. (출처 : 나무위키)

 

"210" 에서 2를 파싱할 수 없었던 이유는, 2진법에서 숫자 2는 자릿수가 올리가는 단위이기 때문입니다.

쉽게 말해 숫자 2가 나오면 자릿수가 올라간다는 뜻입니다.

그렇다면 3진법에서는 숫자 0, 1, 2 만 사용되며 3 이상의 숫자는 사용할 수 없습니다.

 

그럼 숫자 1102 는 어떻게 될까요?

parseInt("1102", 2);

위에서 언급했듯 2진법에선 숫자 2 이상은 파싱할 수 없습니다.  그렇기 때문에 문자열 "110" 까지만 파싱되고, 그 이후 부터는 파싱되지 않습니다. 

parseInt("1102", 2);
>>> 6 // 110 을 2진법으로 파싱한 결과

그렇다면 위에서 "210" 을 2진법으로 파싱한 결과가 NaN인 이유도 이해할 수 있습니다.

parseInt("210", 2)

// 첫 문자열인 "2" 부터 2진법의 범위를 넘기 때문에 더이상 파싱하지 못하고 NaN 리턴

 

두번째 인자를 쓰지 않았을 때 생기는 일

사실상 이 포스팅을 쓰게 된 계기입니다.사실 대부분의 코드에서 (제 경험 한정) parseInt() 의 두번째 인자를 사용한 곳은 거의 볼 수 없었습니다. 그래서 인지 radix 의 default 값이 10 인줄 알고있었지만, 공식문서 어디에도 radix 의 default 값을 명시한 곳은 없었습니다. 

하이라이트 된 부분을 해석하자면,

parseInt()의 두번째 인자가 주어지지 않았을 때 string 의 접두사가 '0x'이라면 16진법, 그 외의 경우엔 10진법으로 간주합니다.

 

즉 두번째 인자가 없을 때  parseInt() 의 매개값으로 "0x" 로 시작하는 문자가 들어간다면(그럴 경우는 적겠지만) 16진법으로 파싱된다는 의미입니다. 

 

이 글을 쓰기 전엔 parseInt("0x")의 결과는 당연히 0일 것이라 생각했습니다.

하지만 결과는 NaN 이 나오죠. radix 값을 입력하지 않았기 때문입니다. 제가 원하는 결과인 0 이 나오려면 radix 값을 10 으로 설정해야합니다. 강조하지만 radix의 default 는 10 이 아니기 때문에 개발자가 꼭 명시해야합니다.

 

결론

parseInt() 함수를 사용할 때 첫번째 인자뿐만 아니라, 두번째 인자까지 꼭 명시해주는 것이 좋습니다. 물론 첫번째 인자만으로도  개발자의 의도에 맞는 결과를 구할 수 있지만 "0x" 처럼 일반적이지 않은 문자열이 들어오는 경우도 대비할 수 있어야합니다.

대부분의 경우에서 parseInt() 를 사용하는 대부분의 경우는 10진법을 기준으로 문자열을 parsing 하기 때문에 parseInt(string, 10) 처럼 코드를 작성하는 습관을 들이면 좋을것이라 생각합니다.