Description
원문 : https://javascriptweblog.wordpress.com/2010/09/27/the-secret-life-of-javascript-primitives/
자바스크립트에서 문자열, 숫자 또는 불리언 원시타입들을 사용할 때마다 여러분은 객체의 그림자와 강압에 숨겨진 세계에 들어가게 됩니다. 그러니 셜록홈즈의 옷장의 먼지를 털어내고 계속 읽어보세요.
기본
객체는 속성들의 집합입니다. 하나의 속성은 객체나 원시타입을 참조할 수 있고, 원시 타입은 값들로 속성을 갖지 않습니다. 자바스크립트에서 원시 타입은 다섯 가지가 있습니다. undefined
, null
, boolean
, string
그리고 number
입니다. 그 외에 모든 것들은 객체입니다. 원시타입 boolean, string, number는 그들의 객체에 대응되는 것들에 감싸질 수도 있습니다. 이 객체들은 각 Boolean
, String
, Number
생성자의 인스턴스들입니다.
typeof true; //"boolean"
typeof Boolean(true); //"boolean"
typeof new Boolean(true); //"object"
typeof (new Boolean(true)).valueOf(); //"boolean"
typeof "abc"; //"string"
typeof String("abc"); //"string"
typeof new String("abc"); //"object"
typeof (new String("abc")).valueOf(); //"string"
typeof 123; //"number"
typeof Number(123); //"number"
typeof new Number(123); //"object"
typeof (new Number(123)).valueOf(); //"number"
원시 타입은 속성이 없는데 왜 "abc".length
는 값을 반환할까?
자바스크립트는 원시 타입과 객체를 쉽게 강제변환하기 때문입니다. 이런 경우에서 문자열 값은 length라는 프로퍼티에 접근했기 때문에 문자열 객체로 강제변환됩니다. 문자열 객체는 찰나의 순간에만 사용되고 바로 가비지 콜렉션에 의해 수집됩니다. 우리는 찰나의 이 생명체를 가둬 분석을 해볼 겁니다.
String.prototype.returnMe= function() {
return this;
}
var a = "abc";
var b = a.returnMe();
a; //"abc"
typeof a; //"string" (still a primitive)
b; //"abc"
typeof b; //"object"
의미있는 많은 조사들과 마찬가지로 우리는 b를 생성했기 때문에 b가 존재하는 한 객체가 자연스럽게 수집되는 것을 방해하여 막았습니다. 하이젠베르크는 살아있습니다. 😉 (strict mode에서는 이렇게 잡을 수 없습니다.)
다음 예시는 가비지 컬렉션을 방해하지 않고 객체의 유형을 확인하는 방법입니다.
Number.prototype.toString = function() {
return typeof this;
}
(123).toString(); //"object"
이러한 방법을 통해 원시타입은 각자의 객체 생성자가 정의한 메소드를 포함한 모든 프로퍼티에 접근할 수 있습니다.
이 객체들은 값들로 강제 변환될 수도 있는가?
주로 그렇습니다. 이러한 유형의 객체들은 단지 래퍼의 역할을 하며 그들의 값은 객체들이 감싸고 있는 원시타입입니다. 필요할 때는 자신들의 값으로 강제 변환되기도 합니다. 이 글에 대한 더 자세한 내용은 여기를 참고하세요.
// 원시값으로 강제변환되는 객체 1
var Twelve = new Number(12);
var fifteen = Twelve + 3;
fifteen; //15
typeof fifteen; //"number" (primitive)
typeof Twelve; //"object"; (still object)
//원시값으로 강제변환되는 객체 2
new String("hippo") + "potamus"; //"hippopotamus"
// 변환되지 않는 객체 ('typeof' 연산자는 여전히 객체로 동작하기 때문)
typeof new String("hippo") + "potamus"; //"objectpotamus"
슬프게도 불리언 객체는 그렇게 쉽게 변환되지 않습니다. 그리고 불리언 객체는 값이 null 이나 undefined가 아니라면 true로 평가됩니다.
if (new Boolean(false)) {
alert("true???");
}
일반적으로 불리언 객체에 값을 명시적으로 요청해야 합니다. 다음은 값이 "truthy"한지 "falsy"한지 결정하는데 도움이 될 수 있습니다.
var a = "";
new Boolean(a).valueOf(); //false
하지만 실제로는 이렇게 하는 것이 더 쉽습니다.
var a = Boolean("");
a; // false
또는 이렇게요.
var a = "";
!!a; //false
형변환을 이용하여 원시 타입에 값을 할당할 수 있을까?
그렇지 않습니다.
var primitive = "september";
primitive.vowels = 3;
primitive.vowels; //undefined;
자바스크립트가 원시 타입에 프로퍼티를 할당하는 것을 감지한다면 원시 타입을 객체로 강제 형변환시켰을 겁니다. 그러나 위의 예시처럼 새로운 객체는 참조값이 없고 즉시 가비지 콜렉션에 의해 수집됩니다.
다음은 실제로 어떤 일이 일어나는지 설명하기 위한 수도 코드입니다.
var primitive = "september";
primitive.vowels = 3;
// 생성된 새로운 객체에 프로퍼티 셋
(new String("september")).vowels = 3;
primitive.vowels;
// 또 다른 객체가 생성되고 이 객체에서 프로퍼티를 찾음
(new String("september")).vowels; //undefined
보시다시피, 이러한 코드는 쓸모없을 뿐 아니라 낭비입니다.
마무리
프로퍼티를 할당하는 것은 원시타입과 달리 객체가 가지는 유일한 장점이지만 이마저도 꽤 의심스럽습니다. 문자열, 불리언, 넘버는 구체적이고 잘 정의된 목적을 가지며 프로퍼티를 갖는 것은 사람들을 혼란스럽게 할 것입니다. 또한 원시 타입은 불변값이므로 객체 래퍼의 프로퍼티를 수정할 수 없습니다.
var me = new String("Angus");
me.length = 2; //(error in strict mode)
me.length; //5 (not 2 - thanks @joseanpg)
me.valueOf(); "Angus"
그럼에도 불구하고 원시타입을 잘 이해하고 원시타입을 사용할 때 어떤 일들이 일어나는지 이해하는 것은 언어를 더 잘 이해하는데 아주 중요한 단계라고 생각합니다. 이 글이 도움이 되었길 바랍니다.