지난 타입과 값 포스트에서 소개했던 자바스크립트에는 네이티브(Natives)라고 하는 몇 가지 내장 타입이 있었습니다. 이번에는 네이티브들에 대해서 간단히 알아보겠습니다.
자주 사용되는 네이티브들을 보면 다음과 같은 모양입니다.
- String()
- Number()
- Boolean()
- Array()
- Object()
- Function()
- RegExp()
- Date()
- Error()
- Symbol()
이 중 Symbol()은 ES6부터 추가되었습니다.
형태를 보면 아시겠지만, 네이티브들은 내장 함수입니다. String("test"); 의 형태로 생성자처럼 사용할 수도 있습니다.
다만 실제 생성자처럼 사용했을때는 원시값을 감싼 객체 래퍼의 형태로 생성됩니다.
생성된 객체 래퍼의 구조를 살펴보겠습니다.
String { "문자열" } 의 형태로 생성된 것을 확인 할 수 있었습니다. 확실히 원시타입처럼 보이지는 않습니다. 비교를 위해 원시타입의 콘솔로그 출력 형태도 한 번 확인해보겠습니다.
다른 속성들 없이 순수한 문자열인 test만 콘솔에 찍히는 모습입니다.
생성자처럼 사용할 수는 있지만, 일반적인 생성자의 결과값과는 다르다는 것을 기억해두시면 되겠습니다.
내부 클래스
위에서 보았듯이, new String("문자열") 을 통해 만든 객체 래퍼는 따로 지정해주지 않았던 속성들이 추가로 붙어있었습니다. 그 중에서도 [[Class]] 라는 이름의 내부 프로퍼티가 있었는데, 이는 typeof로 확인한 타입이 object인 객체들이 가지고 있는 속성입니다. 위의 예시에서는 PrimitiveValue라는 Class값이었습니다.
특이하게도, 이 속성은 직접 접근할 수가 없습니다. 대신 Object.prototype.toString() 이라는 메서드를 이용해 호출할 수 있습니다.
위에서 만들었던 obj가 문자열 객체 래퍼였으므로 String으로 표시되었고, 저 자리에 문자열 대신 배열이 들어갔다면 [object array], 정규식이라면 [object RegExp] 의 모양으로 출력됩니다.
내부 [[Class]] 값은 보통 해당 값과 관련된 내장 네이티브 생성자이지만, 항상 그렇지는 않습니다.
네이티브 생성자가 존재하지 않는 null과 undefined의 경우를 보겠습니다.
Null()이나 Undefined() 같은 생성자는 존재하지 않지만 내부 클래스 값은 Null, Undefined임을 알 수 있습니다. 이 외의 다른 값(문자열, 숫자, 불리언 등등)들은 이러한 박싱 과정을 거치게됩니다.
박싱
원시 값에는 특별한 프로퍼티나 메서드가 없습니다. 따라서 이를 감싸는 객체 래퍼는 원시 값의 부족한 부분들을 채워주는 역할을 합니다.
원시 값들을 제대로 다루기 위해선 꼭 필요한 작업이지만, 프로그래머가 직접 해 줄 필요는 없습니다. 자바스크립트는 원시값들을 알아서 객체 래퍼로 변경합니다. 덕분에 이러한 코드도 실행이 가능합니다.
원래대로라면 이러한 코드는 직접 객체로 만들어주는것이 맞다고 생각할 수 있지만, 이 정도는 브라우저가 스스로 최적화하도록 만들어져있기 때문에 임의로 객체 형태로 만들어주는건 오히려 속도가 저하될 수 있습니다. 특수한 경우가 아니라면 굳이 객체로 만들 필요없이 원시값 그대로 사용하시는게 좋습니다.
그럼에도 불구하고 직접 객체 래퍼를 사용해야 한다면 객체의 속성을 주의하여 박싱하셔야 합니다.
객체는 항상 truthy하기 때문에 참/거짓을 판별하면 무조건 참을 반환하게 됩니다.
언박싱
박싱을 통해 원시 값을 객체 래퍼로 만들었다면, 객체 래퍼에서 원시 값을 추출하는 과정은 언박싱이라고 부릅니다.
valueOf() 메소드를 통해 객체 래퍼의 원시 값을 추출할 수 있습니다.
이 과정은 암시적으로도 일어납니다. 문자열을 원시 값으로 갖는 객체 래퍼 obj의 값에 + 연산자로 문자열을 더해보겠습니다.
새로 만들어진 primitive 변수에 obj의 값을 함께 더해주는 과정에서 암시적으로 valueOf() 메소드가 사용된 것을 알 수 있습니다. typeof() 로 타입을 확인해보니 primitive는 string임을 알 수 있습니다.
생성자
위에서 언급했듯, 네이티브는 생성자로 사용할 수 있습니다. 그러나 반드시 네이티브를 생성자로 사용해야만 하는 경우가 아니라면 권장하는 방식은 아닙니다. 네이티브를 통한 생성은 일반적인 생성자를 사용한 결과와 다른 부분이 꽤 많이 존재해서, 생각지도 못했던 오류와 씨름하게 될지도 모르니 가급적 사용을 자제합시다.
네이티브 생성자들이 가진 특이한 부분들을 몇 가지 살펴보겠습니다.
먼저 Array() 입니다.
배열을 생성하는 Array() 는 생성 시 인자를 숫자 하나만 가질때, 그 숫자만큼의 크기를 가진 빈 배열을 생성합니다.
new Array(3); 처럼 사용한다면 숫자 3을 요소로 갖는 배열이 아닌, 크기가 3인 빈 배열을 생성하게 되니 헷갈리지 않게 주의해야합니다.
다음은 Function() 입니다. 함수 생성자는 함수의 내용이나 인자를 동적으로 정의해야하는 상황에 한해 사용하면 좋습니다. 그 이외의 경우에는 사용하지 않는것이 좋습니다.
대부분의 경우에서 생성자 대신 리터럴을 사용하는 걸 권장하지만 예외가 있는데, RegExp() 입니다. 동적으로 정규식 패턴을 정의할때 유용하게 사용할 수 있고, 실제로도 꽤 사용되는 유틸리티입니다.
Date()와 Error()은 리터럴 형식이 없어 생성자를 사용하는 방법이 유일하고, 유용합니다. 날짜와 시간을 다루는 Date() 객체는 new 키워드를 붙여 생성하는 것이 일반적인데 new를 사용하지 않고 Date()만 사용하게 되면 현재 날짜와 시간에 해당하는 문자열을 반환해주는 특징이 있습니다. Error()는 코드에서 실제로 예외가 발생하면 자동으로 throw되니 굳이 지정해 줄 필요는 없습니다.
마지막으로 가장 특이한 케이스인 Symbol() 입니다. 심볼은 new를 사용하면 되려 오류가 나는 유일한 네이티브 생성자입니다. ES6에서 새롭게 등장한 개념이라 낯설게 느껴지기도 하는데, 유일하게 사용할 수 있는 값이라고 생각하면 좋습니다. 주로 ES6의 내부 로직에 적용하기 위해 고안된 네이티브지만 직접 정의하여 사용하는 것도 가능합니다.
미리 정의된 몇 가지 심볼은 다음과 같이 사용할 수 있습니다.
네이티브의 프로토타입
내장 네이티브 생성자들은 각자의 .prototype 객체를 가집니다. prototype 객체에는 해당 객체의 하위 타입별로 고유한 로직이 담겨있습니다. 예를 들어 String의 프로토타입을 보겠습니다.
문자의 위치를 검색하는 indexOf(), 특정 위치의 문자를 반환하는 charAt(), 문자열을 대문자로 변환하는 toUpperCase() 등이 있습니다.
위에서 생성한건 일반적인 String 객체 래퍼이지만, String 으로부터 프로토타입 위임을 받은 덕분에 이러한 프로토타입 메소드들을 사용할 수 있게 됩니다.
String은 문자열이기 때문에 문자열을 다루는데 적합한 프로토타입 메소드들이 구현되어 있고, 다른 네이티브들도 각자의 특성에 걸맞는 기능들을 가지고 있습니다. 예시로 Number의 경우 숫자에 관련된 메소드들이, Array의 경우 배열에 관련된 메소드들이 있습니다.
다만 이러한 프로토타입은 프로그래머가 임의로 수정이 가능하기 때문에 실수로라도 건드리는 일이 없어야 합니다.
정리
- 자바스크립트에는 원시 값을 감싸는 네이티브라는 객체 래퍼를 지원합니다.
- 각 네이티브에는 원시 값의 특성에 맞는 여러가지 기능이 내장되어 있습니다.
- 드물지만, 네이티브에 따라 생성자로 사용했을때 유용한 경우가 있습니다.
- 기본 프로토타입들은 변경하지 말아야 합니다.
'이론 > Frontend' 카테고리의 다른 글
JavaScript의 강제변환 - 2 (Coercive Type Conversion of JavaScript) (0) | 2021.03.05 |
---|---|
JavaScript의 강제변환 - 1 (Coercive Type Conversion of JavaScript) (0) | 2021.03.02 |
JavaScript의 값 - 2 (Value of JavaScript) (0) | 2021.02.19 |
JavaScript의 값 - 1 (Value of JavaScript) (0) | 2021.02.17 |
JavaScript의 타입 (Type of JavaScript) (0) | 2021.02.15 |
댓글