JavaScript의 데이터 타입은 "원시 타입", "객체 타입" 으로 나뉘어 진다. "원시 타입" 에는 String, Number, Boolean, Null, Undefined, Symbol 이 있으며, "객체 타입"에는 Object, Array, RegExp, Function 등이 포함된다.
이 문장을 수도없이 기억하려고 노력하였다. 어떤 언어를 처음 공부할 때 가장 중요하게 생각하는 것은 그 언어가 가지고 있는 본질적인 성질이기 때문이라고 생각했기 때문이다.
원시 타입과 객체 타입에 대해서 심도(?)있게 공부를 하는 도중 문득 이런 문장을 보고 궁금증에 도달하게 되었다.
"원시타입은 객체가 아니기 때문에, 메소드와 속성을 가질 수 없다."
"그럼 지금까지 내가 써왔던 String.split() 또는 String.toUpperCase() 와 같은 메소드들은 도대체 어떻게 작동이 되는 거지?" 라는 의문과 불안감 속에 이런 의문을 해결하기 위해 자료를 찾기 시작했다.
자료를 찾기 시작한 지, 얼마가 지난 무렵 한 자료를 발견하게 되었는데, 그 자료에는 "래퍼 객체"라는 것에 대해 설명하고 있었다. "내가 모르는 또 다른 무언가가 있구나..." 라는 내게 주는 따끔한 충고와 더불어 "지금이라도 너란 존재를 알게되어서 다행이다" 라는 불현듯하게 터져나오는 안도감까지, 여러 감정들이 공존한 순간이었다.
아무튼 하루 종일 하나 하나씩 살펴 보며 정리를 하기로 마음을 먹었다.
JavaScript에는 총 6개의 원시타입(primitive type)이 있는데, 앞서 말했듯이 String, Number, Boolean, Null, Undefined, Symbol 이 존재한다.
동시에 원시 타입에 대응하는 래퍼 객체(Wrapper object)가 존재하는데 이는 다음과 같다.
- String
- Number
- Boolean
- Symbol
하하....... 6개의 원시 타입을 좋지 않은 머리속에 저장하려고 그렇게 노력을 해왔는데.. 그안에서 또 뭐가 나뉘네....
아무튼 계속 이어서 살펴보자.
Wrapper 말 그대로 무언가를 감싸는 것이라고 생각해 볼 수 있는데, 원시 타입을 감싸 임시 객체로 만들어 주는 것이라고 생각하면 된다.
평소에 String.toUperCase() 메소드를 쓸 경우가 많았는데, 오늘은 그 메소드를 가지고 예제를 만들어 보았다.
코드 첫번째 줄을 보면 word 라는 변수에 'hello' 라는 값을 할당하고, 두 번째 줄에서 문자열 'hello'의 속성(프로퍼티)를 참조하려고 하는 순간, 이 때가 가장 중요하다. 이 순간 JavaScript는 new String(word)를 호출한 것처럼 원시 타입인 String 자료형을 이용한 Wrapper Object(래퍼 객체)를 만들고 프로퍼티에 접근 한다. 중요한 것은 이 과정에서 원본에는 아무런 영향을 미치지 않는다는 것이다.
이렇게 생성된 임시 객체는 프로퍼티의 접근하고 값을 이용한 후에는 지워버린다.
이렇게 이루어지는 단계를 "Auto boxing" 이라고 하는데, 한국어로는 자동 박싱(?) 정도로 번역될 수 있겠다.
Auto boxing이 이루어지는 과정에서 원시 타입 변수에 아무런 영향을 미치지 않고, 원시 타입 변수는 그냥 원시 타입 중 하나인 문자열일 뿐이라는 것에 주목을 해둘 필요가 있다.
결론적으로 "Wrapper Object" 는 원시 값에는 프로퍼티나 메서드가 없으므로, 이에 접근하기 위해 도와주는 고마운 녀석 A, "Auto boxing"을 해주는 고마운 녀석 B, JavaScript, 이 두 친구 덕택에 조금은 편하게 몇몇 원시 타입들(String, Number, Boolean)이 Object(객체) 처럼 동작하여, 편하게(?) 값들을 제어할 수 있구나 정도로 정리할 수 있을 것 같다.
아 ~ 이제 정리 끝이라고 말할려는 찬라에 순간, 모든 시험 문제가 쉽게 느껴질 때 꼭 검토를 안한 한 문제가 틀릴 때가 있듯이, "Wrapper Object" 에도 그런 얘가 존재한다.
여기서는 "Wrapper Object"에 대해 조금은 간과할 수 있는 부분 이 몹쓸 것이 가지고 있는 함정에 대해 다뤄보도록 하겠다.
위에 몹쓸 코드를 보면, 원시 타입의 문자열과는 다르게 String 객체(new String())는 진짜 객체이다.
그렇기 때문에 이 코드에서는 2가지를 알 수 있는데 이는 다음과 같다.
1. 원시 타입 문자열과 String 객체가 동일하지 않다는 것
2. String 객체라도 동일하지 않다는 것, 다시 바꾸어 말하면 String 객체는 개별 객체이기 때문에 자기 자신과만 동일하다는 것
그래서 다음과 같은 코드를 사용할 때 예상하지 못했던 일이 일어날 수도 있다.
false를 래퍼 객체로 감쌌지만 문제는 a가 객체이기 때문에, 예상과는 달리 안에 들어있는 false 값과는 반대의 결과가 나온다.
결론적으로 여기서 이야기하고 싶었던 건, 래퍼 객체를 통해 직접 박싱하는 건 좋은 방법이 아니라는 걸, 그리고 할 수는 있지만 굳이 그렇게 해야하는 필요성이 없다라는 것을 강조한다.
다음 시간에는 String에 대한 기록이다.
< 참고자료 >
[도서] You don't know JS - 카일심슨 지음-
https://javascriptrefined.io/the-wrapper-object-400311b29151
<ES5 series> chapter 7, Wrapper object end
'Language & Framework & Library > JavaScript' 카테고리의 다른 글
ES5 .Intro(6) - 스코프(Scope) (0) | 2019.12.14 |
---|---|
ES5 .Intro(5) - '== vs ===' (0) | 2019.12.14 |
ES5 .Intro(2) - 데이터 타입 (0) | 2019.12.10 |
ES5 .Object(2) - Array(배열) (2) | 2019.11.26 |
ES5 .Object(1) - Object(객체) (2) | 2019.11.22 |