JavaScript/기초

[JavaScript]래퍼 객체(Wrapper Object)

DevStory 2021. 5. 27.

래퍼 객체(Wrapper Object)

이번 포스팅은 JavaScript의 래퍼 객체에 대해 소개합니다.


기본 타입(Primitive Types)

이번 포스팅에서 소개하는 래퍼 객체를 이해하기 전에 JavaScript의 기본 타입(Primitive Types)에 대해 이해할 필요가 있습니다.

 

JavaScript의 기본 타입이란 객체(Object)가 아니며, 메서드와 프로퍼티가 존재하지 않는 데이터입니다. 총 7개의 기본 타입을 제공합니다.

- string

- number

- bigint

- boolean

- undefined

- symbol

- null

 

포스팅 작성일자 기준으로 mozilla에서 언급하고 있는 JavaScript의 기본 타입은 총 7개입니다.

 

Primitive - MDN Web Docs Glossary: Definitions of Web-related terms | MDN

In JavaScript, a primitive (primitive value, primitive data type) is data that is not an object and has no methods or properties. There are 7 primitive data types:

developer.mozilla.org

그리고 기본 타입의 값은 불변이므로 변경할 수 없습니다.(값을 변경하는 것과 값을 다시 할당하는 것은 다릅니다.)

 

다음 예제는 기본 타입의 값이 불변인 것을 보여줍니다.

function addFive(num) {
  num += 5;
}

var num = 0;
console.log(num); // 0

addFive(num);
console.log(num); // 0

매개변수로 전달받은 값에 5를 더하는 addFive() 함수를 정의 후 0으로 초기화된 변수 num을 addFive() 함수의 매개변수로 전달합니다. addFive() 함수가 종료되면, addFive() 함수 내부의 지역 변수인 num도 소멸되므로 addFive() 함수 외부에 존재하는 변수 num의 값은 변경되지 않습니다.

 

다음 예제는 기본 타입의 값을 다시 할당하는 경우입니다.

var num = 0;
console.log(num); // 0

num = 5;
console.log(num); // 5

문자열

문자열은 프로퍼티와 메서드가 존재하지 않는 JavaScript의 기본 타입이라고 언급했지만, 다음 예제를 보면 length 프로퍼티와 indexOf() 메서드를 호출할 수 있습니다.

var strValue = 'JavaScript';

console.log(strValue.length);       // 10
console.log(strValue.indexOf('S')); // 4

위 예제의 실행 결과만 보면, 문자열에서 length 프로퍼티와 indexOf() 메서드를 호출할 수 있으므로 기본 타입이 아닌 객체라고 생각할 수 있습니다.

 

하지만, 다음 예제처럼 문자열 변수에 프로퍼티와 함수를 추가하는 경우 undefined를 반환하거나 타입 에러(TypeError)가 발생합니다.

var strValue = 'JavaScript';

strValue.name = '둘리';
strValue.print = () => {
  console.log('출력');
}

console.log(strValue.name);
console.log(strValue.print());

[실행 결과]

즉, 문자열은 프로퍼티와 메서드를 추가할 수 없으며, 이미 존재하는 프로퍼티와 메서드만 호출할 수 있습니다.

 

아래에서 소개하는 래퍼 객체를 통해 문자열 동작 과정을 살펴봅시다.


래퍼 객체(Wrapper Object)

JavaScript는 null과 undefined를 제외한 5가지 기본 타입(string, number, bigint, boolean, symbol)을 래핑하는 래퍼 객체를 가지고 있습니다.

기본 타입 래퍼 객체
string String
number Number
bigint BigInt
boolean Boolean
symbol Symbol

JavaScript는 내부적으로 위 5개의 기본 타입에 대해 변수를 생성하거나 참조하면, 해당 값을 래핑하는 래퍼 객체를 생성합니다.

 

다음 소스 코드처럼 문자열 변수를 생성하면, 

// 내가 작성한 소스 코드
var strValue = 'JavaScript';

JavaScript 엔진은 내부적으로 new String()을 호출하여 임시적으로 기본 타입인 string을 래퍼 객체인 String으로 변환합니다.

// JavaScript 엔진이 해석하는 소스 코드
var strValue = new String('JavaScript');

 

위 내용을 쉽게 이해하기 위해 다음 예제를 살펴봅시다. 다음 예제는 문자열 변수를 생성하고 length 프로퍼티와 indexOf() 메서드를 호출합니다.

/* 내가 작성한 소스 코드 */
var strValue = 'JavaScript';

console.log(strValue.length);       // 10
console.log(strValue.indexOf('S')); // 4

JavaScript 엔진은 위에서 작성된 소스 코드를 다음과 같이 해석합니다.

/* JavaScript 엔진이 해석하는 소스 코드 */
var strValue = new String('JavaScript');

console.log(new String(strValue).length);       // 10
console.log(new String(strValue).indexOf('S')); // 4

문자열 변수를 사용할 때마다 임시적으로 래퍼 객체로 변환합니다. 따라서, String 객체에서 제공하는 length 프로퍼티와 indexOf() 메서드를 호출할 수 있습니다.

 

그리고 JavaScript 엔진은 임시적으로 변환한 래퍼 객체를 재사용하지 않으며, 한 번 사용한 직후 가비지 수집기에 의해 메모리에서 회수됩니다.

 

이제, 문자열 변수에 프로퍼티와 메서드를 추가할 수 없었던 이유를 살펴봅시다.

 

아래 소스 코드처럼 문자열 변수에 name이라는 프로퍼티를 추가하면,

/* 내가 작성한 소스 코드 */
var strValue = 'JavaScript';

strValue.name = '둘리';

strValue.name;

JavaScript 엔진은 다음과 같이 string을 래퍼 객체로 변환합니다.

/* JavaScript 엔진이 해석하는 소스 코드 */
var strValue = new String('JavaScript');

// strValue를 임시로 객체로 변환 후 name이라는 프로퍼티를 추가함.
// 아래 소스 코드 실행 후 임시로 변환된 래퍼 객체가 소멸되므로 name 프로퍼티는 존재하지 않음.
new String(strValue).name = '둘리';

// 임시로 변환된 래퍼 객체가 소멸되었으므로 name 프로퍼티는 존재하지 않으며, name 프로퍼티에 할당된 값도 소멸됨.
new String(strValue).name;

문자열 변수에 프로퍼티와 메서드를 추가하더라도 임시로 변환된 래퍼 객체가 가비지 수집기에 의해 회수되므로 호출할 수 없습니다. 

 

만약, 기본 타입에 프로퍼티와 메서드를 추가하고 싶다면, new 키워드를 사용하여 명시적으로 래퍼 객체를 생성합니다.

var strValue = new String("Java Script");
strValue.firstName = "Java";
  
strValue.LastName = function() {
  console.log("Script");
};
  
console.log(strValue.firstName); // "Java"
strValue.LastName();             // "Script"

동등 연산자로 비교

기본 타입으로 생성된 변수와 new 키워드를 사용하여 명시적으로 생성된 래퍼 객체는 서로 다른 타입입니다. 래퍼 객체의 타입은 이름 그대로 객체입니다.

 

따라서, 값과 타입을 비교하는 동등 연산자(===)로 기본 타입과 래퍼 객체를 비교하면 false가 반환됩니다.

 

EX 1) 원시 타입 간 비교

console.log('JavaScript' === 'JavaScript'); // true
console.log(29 === 29); // true
console.log(true === true); // false

 

EX 2) 원시 타입과 래퍼 객체의 비교

console.log(new String('JavaScript') === 'JavaScript'); // false
console.log(new Number(29) === 29); // false
console.log(new Boolean(true) === true); // false

 

EX 3) 래퍼 객체 간 비교

console.log(new String('JavaScript') === new String('JavaScript')); // false
console.log(new Number(29) === new Number(29)); // false
console.log(new Boolean(true) === new Boolean(true)); // false

 

EX 4) valueOf()를 사용하여 원시 타입과 래퍼 객체의 값의 비교

console.log((new String('JavaScript')).valueOf()  === 'JavaScript'); // true
console.log((new Number(29)).valueOf()  === 29); // true
console.log((new Boolean(true)).valueOf()  === true); // true

래퍼 객체로 생성된 변수는 실제 값이 아닌 참조 값을 가집니다. 따라서, 래퍼 객체의 실제 값을 비교하려면 valueOf() 메서드를 호출하여 실제 값을 가져와야 합니다.


정리

  • 원시 타입 : string, number, bigint, boolean, null, undefined, symbol
  • 원시 타입에 대응되는 래퍼 객체 : String, Number, BigInt, Boolean, Symbol
  • 원시 타입은 프로퍼티와 메서드를 정의할 수 없습니다.
  • new 키워드를 사용하여 원시 타입을 래퍼 객체로 생성할 수 있지만, 주로 사용하는 방법은 아닙니다.
  • 자바스크립트 엔진에 의해 래퍼 객체는 한 번 사용 후 소멸됩니다.
반응형

댓글