원시 타입 값에서 메서드를 쓸 수 있는 이유 (+왜 숫자 리터럴에서는 안 될까?)

2025. 6. 17. 03:06·Frontend/JS, TS

메서드는 정적 메서드와 인스턴스 메서드로 구분할 수 있습니다. 정적 메서드는 인스턴스 없이 바로 호출할 수 있는 메서드를 말하고, 인스턴스 메서드는 인스턴스를 주체로 하여 호출되는 메서드를 말합니다. Number.prototype.toString, String.prototype.split 등이 인스턴스 메서드입니다.

 

그런데 원시형 타입인 숫자나 문자열이 어떻게 메서드를 가질 수 있는 걸까요? 메서드는 객체에 프로퍼티로 할당된 함수를 말하는 건데 말입니다. 우리는 어떻게 원시형 타입을 마치 객체처럼 다룰 수 있는 걸까요? 이 메서드는 어디에 있는 걸까요?

 

 

원시형 타입과 객체 래퍼 타입

자바스크립트는 원시형 타입 값을 자동으로 객체로 래핑(wrapping)합니다. 예를 들어 primitive string 값이 프로퍼티에 접근하거나 메서드를 실행하려 하면, 자바스크립트는 내부적으로 해당 값을 String 객체 타입으로 변환합니다. 이 String 객체 타입은 문자열의 값을 알고 있고, 문자열만의 프로퍼티와 메서드도 가지고 있습니다. 이러한 타입을 객체 래퍼(object wrapper) 타입이라고 하며, 원시형 타입의 이름을 그대로 차용해 String, Number, Boolean, Symbol이라고 부릅니다.

 

생성자로써 객체 래퍼

자바스크립트는 string과 String을 다르게 취급합니다. new 키워드와 함께 String을 생성자로써 호출하면 반환된 문자열은 object 타입이 됩니다. 따라서 객체 래퍼를 생성자로 사용하지 않는 것이 좋습니다.

const greetingKR = '안녕하세요';
console.log(typeof greetingKR); // 'string'

const greetingEN = new String('hello');
console.log(typeof greetingEN); // 'object'

 

참고로 valueOf 메서드를 사용하면 생성자로 만든 객체에서 원시 값을 얻을 수 있습니다.

const value = greetingEN.valueOf();
console.log(value); // 'hello'
console.log(typeof value); // 'string'

 

함수로써 객체 래퍼

객체 래퍼를 new 키워드 없이 함수로써 단독 호출할 경우, 인자로 받은 값을 원시 타입으로 변환합니다. 일반적으로 객체 래퍼를 생성자로 사용할 일은 거의 없고(권장되지도 않으며), 타입을 변환해야 할 때 사용하는 경우가 많습니다.

const numeric = Number('1234'); // 1234
console.log(typeof numeric); // number

 

참고 자료

  • 원시값의 메서드 - 원시값을 객체처럼 사용하기
  • MDN String - 문자열 원형과 String 객체의 차이

 

여기까지가 객체 래퍼에 대한 이야기이고, 이제부터는 제 궁금증에 대한 이야기를 하려고 합니다.

숫자 리터럴을 객체처럼 사용하기

이처럼 자료형의 프로퍼티나 메서드에 접근할 때 자바스크립트가 객체 래퍼로 자동 변환하기 때문에, 다음과 같이 number와 같은 원형 타입 값도 메서드를 사용할 수 있습니다.

const num = 123;
num.toString(); // 정상

 

그런데, 여기서 숫자 리터럴에서 메서드를 사용할 수 없다는 거 아시나요?


일반적으로 리터럴에서 직접적으로 메서드를 실행해도 문제 없이 작동하는데요. 숫자 리터럴에서는 특이하게도 Syntax Error가 발생합니다.

'hello, world!'.toUpperCase(); // 정상
[1, 2, 3].join(''); // 정상
123.toString(); // Uncaught SyntaxError: Invalid or unexpected token

 

Syntax Error란?

Syntax Error는 코드의 문법이 틀린 경우에 발생하는 오류입니다. 코드가 실행되기 전 컴파일 과정에서 구문 분석기(Parser)에 의해 소스 코드가 분석되는데요. 이때 소스 코드가 문법 규칙에 맞지 않으면 구문을 제대로 분석할 수 없게 됩니다. 예를 들어 오타가 있거나, 괄호의 쌍이 맞지 않거나, 세미콜론으로 문장 끝을 명시해야 하는 언어에서 세미콜론을 누락한 경우가 그렇습니다.

 

그런데 왜 123.toString()에서 Syntax Error가 발생할까요? 기능적으로 안되는 거면 런타임 오류일텐데, 코드를 실행하기도 전에 문법적으로 틀렸다는 게 언뜻 봐서는 이해가 되지 않습니다. 문자열이나 배열 리터럴 등에서는 문제가 없는데 말이죠.


그리고 왜 123.toString()은 안 되는데, num.toString()은 되는 걸까요?

 

이는 수를 표현하는 방식 때문입니다.

 

수에도 온점, 객체에도 온점

수는 정수, 실수, 유리수, 무리수 ... 등 다양한 집합으로 나뉘고 그 범위도 매우 큽니다. 일상에서는 정수를 많이 사용하지만 사실 정수인 123도 연속적인 수 가운데 123.000···0을 단축하여 표현한 것입니다.

 

자바스크립트에서도 마찬가지로 123.0을 123, 123.처럼 표현할 수 있습니다. 정수와 실수 타입을 구별하는 언어도 있지만, 자바스크립트에서는 숫자라면 모두 number 타입이며, 소수점(.)을 사용하여 나타낼 수 있습니다.

 

이 온점(.)을 객체의 내부 값에 접근할 때에도 사용하죠. 이 부분에서 문제가 발생하는 것입니다.

 

123.toString() 파싱 과정

인간은 123.toString()을 다음과 같이 나누어 이해합니다.

  • 123 : 숫자 리터럴
  • . : 프로퍼티/메서드에 접근하기 위한 문법
  • toString() : 함수

하지만 구문 분석기는 이렇게 이해합니다.

  • 123. : 숫자 리터럴 (부동소수점 형태로 파싱)
  • toString() : ??? => 점으로 이어지지 않은 예상치 못한 식별자

앞서 123.도 123을 달리 표현한 거라고 말씀드렸습니다. 구문 분석기는 메서드에 접근하기 위한 온점(.)을 숫자의 일부로 인식하고, 나머지를 의미를 알 수 없는 토큰으로 판단합니다. 숫자와 뒷부분 토큰을 이을 수 있는 유효한 구문이 없기 때문입니다. 이렇게 Syntax Error를 발생한 것입니다.

 

숫자 리터럴 객체처럼 쓰는 방법

다음과 같이 사용하면 숫자 리터럴에서 직접 메서드에 접근할 수 있습니다.

123..toString();
123.0.toString();
(123).toString();

정리

"이펙티브 타입스크립트"라는 책을 읽으면서 "객체 래퍼 타입"에 대한 이야기가 나와서 평소 궁금하던 점에 대해 이유를 찾아보고 정리해보았습니다.

사실 숫자 리터럴을 객체처럼 쓸 일은 거의 없지만, 파싱이 인간이 의도한 것과 다르게 나타날 수 있다는 점을 알 수 있었습니다.

 

참고로 타입스크립트에서 숫자 리터럴에 메서드를 사용하면, 원인을 바로 이야기해주는데요.

An identifier or keyword cannot immediately follow a numeric literal.
식별자 또는 키워드는 숫자 리터럴 바로 뒤에 올 수 없습니다.

 

타입스크립트가 타입 시스템을 제공할 뿐만 아니라 이러한 점에서도 이점이 있다는 것을 느끼게 되었네요.

저작자표시 비영리 변경금지 (새창열림)

'Frontend > JS, TS' 카테고리의 다른 글

객체 리터럴 타입과 원시 타입 간 인터섹션 타입이 never가 아닌 이유  (0) 2025.08.09
브랜딩 기법 (Branded Type)  (0) 2025.08.09
문자열을 배열로 만들 때 Array.from과 split 차이점 (feat. 유니코드)  (0) 2025.04.28
프로토타입(Prototype) 총정리  (0) 2024.02.01
Call by Sharing  (0) 2024.01.30
'Frontend/JS, TS' 카테고리의 다른 글
  • 객체 리터럴 타입과 원시 타입 간 인터섹션 타입이 never가 아닌 이유
  • 브랜딩 기법 (Branded Type)
  • 문자열을 배열로 만들 때 Array.from과 split 차이점 (feat. 유니코드)
  • 프로토타입(Prototype) 총정리
톱치
톱치
나를 위한 기록을 합니다
  • 톱치
    기록
    톱치
  • 전체
    오늘
    어제
  • 블로그 메뉴

    • 홈
    • 방명록
    • 글쓰기
    • 전체보기 (51)
      • Articles (0)
      • Frontend (3)
        • JS, TS (16)
        • HTML, CSS (5)
        • React (6)
        • Dart (3)
      • Backend (6)
      • Others (3)
      • Algorithm (5)
      • 회고 (4)
  • 링크

    • GitHub
  • 태그

    object
    css
    todolist
    node.js
    BFS
    javascript
    회고
    Redux
    dart
    token
    React
    프리코스
    ts
    js
    TypeScript
    login
    우아한테크코스
    Node
    programmers
    BCrypt
  • hELLO· Designed By정상우.v4.10.3
톱치
원시 타입 값에서 메서드를 쓸 수 있는 이유 (+왜 숫자 리터럴에서는 안 될까?)
상단으로

티스토리툴바