이번 포스팅에서는 자바스크립트의 네이티브 객체들에 대해 알아보고자 한다.
네이티브 객체는 특정 환경(브라우저 등의 클라이언트 프로그램, 또는 Node.js 등의 런타임)에 종속되지 않은, ECMAScript 명세의 내장 객체를 말한다. 우리가 많이 사용하는 네이티브들은 다음과 같다. 짐작이 가는 사람들도 있겠지만, 네이티브 객체는 사실상 내장 함수이다.
- String()
- Number()
- Boolean()
- Array()
- Object()
- Function()
- RegExp()
- Date()
- Error()
- Symbol()
네이티브는 생성자처럼 사용할 수 있지만 실제로 생성되는 결과물은 예상과 다른 경우가 많다.
// 자바처럼 String() 생성자와 비슷하게 보일 수도 있겠다.
var a = new String("Hello World");
console.log(s.toString()); // "Hello World"
// 하지만 생성자는 아니다.
var a = new String("abc");
typeof a; // "object"
a instanceof String; // true
Object.prototype.toString.call(a); // "[object String]"
여기에서 new String("abc")는 원시 타입 string "abc"가 아니라 "abc"를 감싸는 문자열 래퍼를 생성한다.
typeof가 object인 값(ex. 배열 등)의 경우 [[Class]]라는 내부 프로퍼티가 추가로 붙는다. 이 프로퍼티는 직접 접근할 수가 없고 Object.prototype.toString()이라는 메서드에 값을 넣어 호출함으로써 존재를 알 수가 있다.
Object.prototype.toString.call([1,2,3]); // "[object Array]"
Object.prototype.toString.call(/regex-literal/i); // "[object RegExp]"
원시 값들의 경우 null과 undefined는 내부 클래스값이 Null, Undefined로 나타나며, 그 밖의 문자열, 숫자, 불리언 등은 단순 원시값이 해당 객체 래퍼(Wrapper) 클래스로 자동 박싱됨을 알 수 있다.
객체 래퍼는 정말 중요하다. 원시값은 프로퍼티나 메서드가 없기 때문에 .length()나 .toUpperCase()로 접근하려면 원시 값을 객체 래퍼로 감싸주어야 한다. 자바스크립트는 이 과정이 자동으로 일어나기 때문에 아래와 같은 코드가 가능한 것이다.
var a = "abc";
a.length; // 3
a.toUpperCase(); // "ABC"
Symbol은 ES6에서 처음 선보인, 새로운 원시 값 타입이다. 심벌은 충돌 염려 없이 객체 프로퍼티로 사용이 가능한, 특별한 '유일 값'이다. 주로 ES6의 특수한 내장 로직에 쓰기 위해 만들어졌다. 심벌은 프로퍼티명으로 사용할 수 있으나 프로그램 코드나 개발자 콘솔 창에서 심벌의 실제 값을 보거나 접근하는 것은 불가능하다.
ES6에는 심벌 몇 개가 미리 정의되어 있는데 Symbol.create, Symbol.iterator 식으로 Symbol 함수 객체의 정적 프로퍼티로 접근한다.
obj[Symbol.iterator] = function(){ /* ... */ };
심벌을 직접 정의하려면 Symbol() 네이티브를 사용한다. Symbol()은 앞에 new를 붙이면 에러가 나는 유일한 네이티브 생성자이다. 심벌은 객체가 아니다. 단순한 스칼라 원시값이다.
var mySym =Symbol("myOwnSymbol");
mySym; // Symbol(myOwnSymbol)
mySym.toString(); // "Symbol(myOwnSymbol)"
typeof mySym; // "symbol"
var a = {};
a[mySym] = "foobar";
Object.getOwnPropertySymbols(a); // [ Symbol(myOwnSymbol) ]
내장 네이티브 생성자는 각자의 .prototype 객체를 가진다.(ex. Array.prototype, String.prototype 등) 프로토타입 객체에는 해당 객체의 하위 타입별로 고유한 로직이 담겨있다. 이를테면 문자열 원시값을 박싱으로 확장한 것까지 포함하여 모든 String 객체는 기본적으로 String.prototype 객체에 정의된 메서드에 접근할 수 있다. 프로토타입 위임 덕분에 모든 문자열이 이 메서드들을 같이 쓸 수 있다.
참고자료
- <YOU DON'T KNOW JS (타입과 문법, 스코프와 클로저)> 카일 심슨 저
'Prog. Langs & Tools > JavaScript' 카테고리의 다른 글
JS #15. 이벤트 루프 (Event Loop) (0) | 2020.12.07 |
---|---|
JS #14. 스코프(Scope) (0) | 2020.09.07 |
JS #12. 타입과 값(Type and Value) (0) | 2020.07.02 |
JS #11. 자바스크립트 제너레이터(Generator) (0) | 2020.06.19 |
JS #10. 자바스크립트 프로미스(Promise) (0) | 2020.06.11 |