Devhyun

메뉴

현재 화면 위치

데브현 메인 블로그 포스트

타이틀

자바스크립트의 자료형 판정에 대해

2019.10.23
핫한 길다란

아래는 Qiita에 개재된 「JavaScriptの「型」の判定について」를 번역한 내용입니다.

다소 의역이 있어 어색한 부분이 있어도 양해 부탁드립니다. 🙉

원문 보기

자바스크립트의 자료형에 대해 관련된 세세한 사양에 대해, 간단히 정리했습니다.

5개의 primitive 자료형의 판정

Javascript의 자료형은 수치(number), 문자형(string), 불린(boolean), null, undefined의 5개의 원시타입이 있습니다. 이것들은 typeof연산자를 사용하여 판별할 수 있습니다. 다만, null만 사양과 달리 object를 리턴합니다.

※ ES6 에는 Symbol이 추가되었습니다.

typeof 'str';     // 'string'
typeof 1;         // 'number'
typeof true;      // 'boolean'
typeof null;      // 'object' (ECMAScript표준규격에의하면 독립적인 자료형이지만...)
typeof undefined; // 'undefined'

그 외에는 전부 오브텍트 입니다. 단, 함수 오브젝트만 특별히 function 입니다.

typeof {}; // 'object'
typeof []; // 'object'
typeof function() {}; // 'function' 함수오브젝트는 특별취급

오브젝트의 [[class]]를 사용한 판정

원시자료형은 판별이 가능하지만, 각양각색의 다양한 오브젝트(Object, Array 등)의 판별은 할 수 없습니다. 하지만, Array나 Object의 구별을 하고 싶은 경우가 있을지도 모릅니다.

그래서, Object.prototype.toString을 이용하여, 오브젝트의 [[class]]내부의 프로퍼티를 취득하는 방법이 종종 사용되곤 합니다. 콘솔에 출력해보면, [obejct [[class]]]이러한 형태로 됩니다.

var toString = Object.prototype.toString

toString.call({});                // [object Object]
toString.call([]);                // [object Array]
toString.call(function() {});    // [object Function]
toString.call(new Error());       // [object Error]
toString.call(new Date());        // [object Date]
toString.call(JSON);              // [object JSON]
toString.call(Math);              // [object Math]
toString.call(new RegExp());      // [object RegExp]
toString.call(new String('str')); // [object String]
toString.call(new Number(1));     // [object Number]
toString.call(new Boolean(true)); // [object Boolean]

마지막 3개는 각각 문자열(string), 수치(number), 불린형(boolean)의 리터럴(literal) 형태가 아닌 래퍼 오브젝트(Wrapper Object)입니다. 래퍼 오브젝트란 string, number, boolean의 세가지 원시타입에 대해 메서드를 호출할 때, 메서드 실행용으로 일시적으로 생성되는 오브텍트 입니다. 그렇기 떄문에, 생성자를 사용하지 않고 toString을 호출할 수 있습니다.

toString.call('str'); // [object String]
toString.call(1);     // [object Number]
toString.call(true);  // [object Boolean]

또한, ECMAScript5에서, null이나 undefined에도 [[class]]을 반환하게끔 되었습니다.
참고: MDN공식 문서 toString

toString.call(null);      // [object Null]
toString.call(undefined); // [object Undefined]

이로서, 표준 생성자로 생성된 오브젝트와 구별이 가능한 것을 알 수 있었습니다.

constructor 프로퍼티를 활용한 판정

문제가 있다면 자발적으로 실행된 생성자(new 예약어를 통한 할당)의 오브젝트는 Object.prototype.toString을 사용해도 [object Object]의 결과만 나옵니다.

function MyClass() {}
var obj = new MyClass();
Object.prototype.toString.call(obj); // [object Object]

이럴 때 판별하는 방법은 constructor프로퍼티를 사용할 수 있습니다.

obj.constructor === MyClass; // true

그러나, 문자열로서는 취득이 어렵고 더욱더 constructor프로퍼티가 재정의 되는 위험이 있습니다. 또한, 생성자의 prototype 프로퍼티가 변경될수도 있고, 의도와 다른 일이 발생할 수 있습니다.

obj.constructor === 'MyClass'; // false

obj.constructor = Array;     // constructor 프로퍼티를 재정의
obj.constructor === MyClass; // false

function MyClass2() {}  // 새로운 생성자 정의
MyClass2.prototype = {}; // 생성자의 prototype를 변경
var obj2 = new MyClass2();
obj2.constructor === MyClass2; // false
obj2.constructor === Object;   // true

확실한 판정 방법이라고는 할 수 없겠네요.

instanceof 연산자를 활용한 판정

instanceof 연산자는, 오브젝트가 어떤 생성자로부터 생성되었는지를 판별할 때 사용합니다. 오브젝트의 확장된 자료형으로 환정에 사용합니다.

function MyClass() {}
var obj = new MyClass();
obj instanceof MyClass; // true
obj instanceof Array;   // false

여기서 instanceof 연산자의 구동방식에 대해 생각해보겠습니다. instanceof 연산자는 내부적으로는 오브젝트 자신의 프로토타입 체인의 생성자의 prototype가 포함되어 있는지를 체크합니다.

참고: MDN공식 문서 instanceof

obj instanceof MyClass; // true
obj.__proto__ === MyClass.prototype; // true

obj instanceof Object;  // true
obj.__proto__.__proto__ === Object.prototype; // true

그래서, 오브젝트의 프로토타입이 재정의 되는 경우에는 instanceof의 반환값도 달라집니다.

obj.__proto__ = Array.prototype;
obj instanceof MyClass; // false
obj instanceof Array; // true

이것도 확실한 판정방법이라고 할 수는 없겠네요.

결론

표준 생성자로부터 생성된 오브젝트의 판정에는 Object.prototpye.toString을 사용하면 좋습니다. 표준이 아닌 경우 판정하는 방법에는 여러가지 방법이 있지만, 위에서 제시했던 2가지 모두 확실한 방법이라고 할 수는 없습니다. _proto_프로퍼티의 재정의가 절대 없다와 같은 규약을 정한 상태에서 판정하면 좋겠죠.

0개의 댓글

로그인을 하시면 댓글을 작성할 수 있어요 !
목록으로 가기