본문 바로가기

JavaScript

모던 자바스크립트 튜토리얼 | 원시값의 메서드

 

 

 

원시값의 메서드

 

ko.javascript.info

자바스크립트는 원시값(문자열, 숫자등)을 마치 객체처럼 다룰 수 있게 해줍니다. 원시값에도 객체에서처럼 메서드를 호출할 수 있습니다. 원시값은 객체가 아닙니다. 원시값과 객체는 다음과 같은 차이가 있습니다.

 

원시값

- 원시형 값입니다.

- 원시값의 종류는 문자(string), 숫자(number), bigint, 불린(boolean), 심볼(symbol), null, undefined 형으로 총 일곱가지입니다.

 

객체

- 프로퍼티에 다양한 종류의 값을 저장할 수 있습니다.

- { name: "John", age: 30} 와 같이 대괄호 {}를 사용해서 만들 수 있습니다. 자바스크립트에는 여러 종류의 객체가 있는데 함수도 객체의 일종입니다. 

 

객체의 장점 중 하나는 함수를 프로퍼티로 저장할 수 있다는 것입니다. 

 

let john = {
  name: "John",
  sayHi: function() {
    alert("친구야 반갑다!");
  }
};

john.sayHi(); // 친구야 반갑다!

 객체 john을 만들고 거기에 메서드 sayHi를 정의해보았습니다. 자바스크립트는 날짜, 오류, HTML 요소(HTML Element)등을 다룰 수 있게 해주는 다양한 내장 객체를 제공합니다. 이 객체들은 고유한 프로퍼티와 메서드를 가집니다. 하지만 이런 기능을 사용하면 시스템 자원이 많이 소모된다는 단점이 있습니다. 객체는 원시값보다 무겁고 내부 구조를 유지하기 위해 추가 자원을 사용하기 때문입니다. 

 

원시값을 객체처럼 사용하기

자바스크립트 creator는 다음과 같은 모순적인 상황을 해결해야 했습니다. 

- 문자열이나 숫자와 같은 원시값을 다루어야 하는 작업이 많은데, 메서드를 사용하면 작업을 수월하게 할 수 있을 것 같다는 생각이 듭니다.

- 그런데 원시값은 가능한 한 빠르고 가벼워야 합니다.

 

조금 어색해 보이지만 자바스크립트 창안자는 다음과 같은 방법을 사용해 해결책을 모색합니다. 

 

1. 원시값은 원시값 그대로 남겨둬 단일 값 형태를 유지합니다.

2. 문자열, 숫자, 불린, 심볼의 메서드와 프로퍼티에 접근할 수 있도록 언어 차원에서 허용합니다. 

3. 이를 가능하게 하기 위해, 원시값이 메서드나 프로퍼티에 접근하려 하면 추가 기능을 제공해주는 특수한 객체, "원시 래퍼 객체(object wrapper)"를 만들어 줍니다. 이 객체는 곧 삭제됩니다. 

 

"래퍼 객체"는 원시 타입에 따라 종류가 다양합니다. 각 래퍼 객체는 원시 자료형의 이름을 그대로 차용해, String, Number, Boolean, Symbol라고 부릅니다. 래퍼 객체마다 제공하는 메서드 역시 다릅니다. 인수로 받은 문자열의 모든 글자를 대문자로 바꿔주는 메서드 str.toUpperCase()를 예로 들어보겠습니다.

 

let str = "Hello";

alert( str.toUpperCase() ); // HELLO

 

아래는 str.toUpperCase()가 호출될 때 내부에서 실제로 일어나는 일입니다.

1. 문자열 str은 원시값이므로 원시값의 프로퍼티(toUpperCase)에 접근하려는 순간 특별한 객체가 만들어집니다. 이 객체는 문자열의 값을 알고 있고, toUpperCase()와 같은 유용한 메서드를 가지고 있습니다.

2. 메서드가 실행되고, 새로운 문자열이 반환됩니다.(alert 창에 이 문자열이 출력됩니다.)

3. 특별한 객체는 파괴도고, 원시값 str만 남습니다.

 

이런 내부 프로세스를 통해 원시값을 가볍게 유지하면서 메서드를 호출할 수 있는 것입니다. 자바스크립트 엔진은 위 프로세스의 최적화에 많은 신경을 씁니다. 원시 래퍼 객체를 만들지 않고도 마치 원시 래퍼 객체를 생성(명세에 언급됨)한 것처럼 동작하게끔 해줍니다. 

 

숫자형도 고유한 메서드를 지원합니다. 메서드 toFixed(n)을 이용하면 원하는 자리에서 소수점 아래 숫자를 반올림할 수 있습니다.

let n = 1.23456;

alert( n.toFixed(2) ); // 1.23

String / Number / Boolean을 생성자론 쓰지 맙시다.

Java등의 몇몇 언어에선 new Number(1)  또는 new Boolean(false)와 같은 문법을 사용해 원하는 타입의 "래퍼 객체"를 직접 만들 수 있습니다. 자바스크립트에서도 하위 호완성을 위해 이 기능을 남겨 놨는데, 이런 식으로 래퍼 객체를 만드는 건 추천하지 않습니다. 다음과 같은 몇몇 상황에서 혼란을 불러일으키기 때문입니다. 

alert( typeof 0 ); // "number"

alert( typeof new Number(0) ); // "object"!

객체는 논리 평가 시 항상 참을 반환하기 때문에 아래 예시에서 얼럿창은 무조건 열립니다. 

alert( typeof 0 ); // "number"

alert( typeof new Number(0) ); // "object"!

그런데 new를 붙이지 않고 String / Number / Boolean을 사용하는 것은 괜찮습니다. new 없이 사용하면 상식에 맞게 인수를 원하는 형의 원시값(문자열, 숫자, 불린 값)으로 바꿔줍니다. 

 

let num = Number("123"); // 문자열을 숫자로 바꿔줌

 null, undefined에는 메서드가 없습니다. 특수 자료형인 null과 undefined의 원시값(null / undefined)은 위와 같은 법칙을 따르지 않습니다. 이 자료형과 연관되는 "래퍼 객체"도 없고 메서드도 제공하지 않습니다. 어떤 의미에서는 두 자료형이 "가장 원시적"이라고 할 수 있을 것 같습니다. 두 자료형에 속한 값의 프로퍼티에 접근하려 하면 에러가 발생합니다. 

alert(null.test); // error

문자열에 프로퍼티를 추가할 수 있을까?

let str = "Hello";

str.test = 5;

alert(str.test);

엄격 모드인지 아닌지에 따라 결과가 나뉜다. 

1. undefined(비엄격 모드)

2. An error(엄격 모드)

 

1. str의 프로퍼티에 접근하려고 하면 "래퍼 객체"가 만들어집니다.

2. 엄격 모드에선 래퍼 객체를 수정하려 할 때 에러가 발생합니다. 

3. 비엄격모드에선 에러가 발생하지 않습니다. 래퍼 객체에 프로퍼티 test가 추가됩니다. 그런데 래퍼 객체는 바로 삭제되기 때문에 마지막 줄이 실행될 땐 프로퍼티 test를 찾을 수 없습니다. 위 예시를 통해 원시값과 객체는 다르다는 것을 다시한번 확인할 수 있습니다. 원시값은 추가 데이터를 저장할 수 없습니다.