IT_Programming/JavaScript

자바스크립트 완벽가이드 - 9.7 객체 타입 판단하기

JJun ™ 2015. 1. 2. 00:47
  • typeof 연산자 사용 (기본 타입을 객체와 구별하는데 가장 유용)
  • typeof undefined 는 'undefined', typeof null은 'object'
  • 배열은 객체이기 때문에 타입도 'object'
  • 함수는 객체이긴 하지만 타입은 'function'

 


instanceof 와 constructor

  • instanceof
- 기본타입이나 함수가 아니라 객체일때 더 많은 정보를 얻기 위해 사용
x instanceof Array    // x가 배열이라면 true 
- 왼쪽은 테스트될 값, 오른쪽은 클래스를 정의할 수 있는 생성자 함수
- 객체는 자신이 속한 클래스와 상위 클래스의 인스턴스가 된다 (객체 o에 대해서 o instanceof Object는 항상 true)
- 함수에 대해서도 작동
// 아래 모든 표현은 함수 f에 대해 true
typeof f == "function"
f instanceof Function
f instanceof Object
  • constructor
- 객체가 특정한 클래스의 인스턴스고 그 클래스의 하위 클래스의 인스턴수는 아니라는 사실을 테스트할 때 그 객체의 constructor 프로퍼티를 검사
var d = new Date();
var isobject = d instanceof Object;   // true
var realobject = d.constructor == Object;   // false
  • instanceof 와 constructor의 한 가지 단점 : 이미 알고 있는 클래스만 테스트 가능


객체 타입 지정을 위한 Object.toString()

  • 모르는 객체를 조사하는데 유용
  • 확장된 typeof 검사

 

 function getType(x) { if(x == null) return 'null';   var t = typeof x; if(t != "object") return t;   // 객체의 클래스 값을 얻기 위해 시본 toString() 메서드 사용 var c = Object.prototype.toString.apply(x); // '[object class]' 반환 c = c.substring(8, c.length-1); // '[object'와 ']' 를 벗겨낸다   if(c != "Object") return c;   // c가 'Object'라는 결과 얻으면, 여기로 온다 // x가 실제로 그냥 일반적인 객체인지 검사 if(x.constructor == Object) return c;   // 사용자가 정의한 클래스를 위해서 객체의 프로토타입에서 상속받았으며 문자열 값을 가진 classname이란느 프로퍼티 찾음 if("classname" in x.constructor.prototype && typeof x.constructor.prototype.classname == "string") return x.constructor.prototype.classname;   return "<unknown type>"; }

 


오리 타이핑

  • 어떤 클래스가 정의한 모든 메서드를 구현하면, 그것은 그 클래스의 인스턴스이다
  • 다른 클래스에서 메서드를 빌려오는 클래스들을 연결할 때 유용
  • 객체가 다른 클래스에서 메서드를 빌려왔는지 검사 예)
// c.prototype 에서 있는 각 메서드 프로퍼티가 o에서 빌려온 것이라면 true반환
// 만약 o가 객체라기 보다 함수라면 o자체보다 o의 프로토타입을 테스트한다
// 이 함수에서 메서드는 재구현된 것이 아니라 복사된 것이어야 한다
// 만약 클래스가 메서드를 빌려온 후 이를 재작성하면, false 반환
function borrow(o,c) {
   // 만약 무언가의 인스턴스라면, 당연히 그것의 메서드가 있으므로 true
   if(o instanceof c) return ture;
 
   // 내장 타입의 메서드는 열거될 수 없기 때문에 이런 메서드를 빌려온 것인지 검사하는 것은 불가능
   // 이럴 때는 예외를 발생시키는 대신 "알수 없다" 라는 대답의 일종으로 undefined 반환 
   // undefined 는 false와 상당히 유사하게 작동하지만 필요하다면 호출자가 이를 false와 구별할 수 있다.
   if(c == Array || c == Boolean || c == Date || c == Error || c == Function || c == Number || c == RegExp || c == String)
      return undefined;
 
   if(typeof o == "function") o = o.prototype;
   var proto = c.prototype;
   for(var p in proto) {
      // 함수가 아닌 프로퍼티는 무시
      if(typeof proto[p] != "function") continue;
      if(o[p] != proto[p]) return false;
   }
   return true;
}
  • 객체가 메서드를 제공하는지 검사 예)
// 만약 o의 메서드가 c.prototype에 있는 모든 메서드와 이름이 같고 인자 개수가 같다면 true 반환, 그렇지 않다면 false
// 만약 c가 열거될 수 없는 메서드의 내장 타입이면 예외를 발생
function provides(o,c) {
   // 만약 o가 실제로는 c의 인스턴스라면 명백히 c처럼 보인다
   if(o instanceof c) return true;
 
   // 만약 객체대신 생성자가 전달되면, 그것의 프로토타입을 사용
   if(typeof o == "function") o = o.prototype;
 
   // 내장 타입의 메서드는 얼거될 수 없기 때문에 undefined 반환
   // 그렇지 않으면 객체가 내장 타입을 제공하는 것처럼 보인다
   if(c == Array || c == Boolean || c == Date || c == Error || c == Function || c == Number || c == RegExp || c == String)
      return undefined;
 
   var proto = c.prototype;
   for(var p in proto) {   // c.prototype 에 있는 모든 프로퍼티에 대해 반복
      // 함수가 아닌 프로퍼티는 무시
      if(typeof proto[p] != "function") continue;
      // o에 같은 이름의 프로퍼티가 없으면 false 반환
      if(!(p in o)) return false;
      // 만약 프로퍼티가 함수가 아니면 false 반환
      if(typeof o[p] != "function") return false;
      // 두 함수의 전달인자 개수가 다르면 false 반환
      if(o[p].length != proto[p].length) return false;
   }
   return true;
}

 

  • 배열과 유사한 객체를 테스트하기 예)
function isArrayLike(x) {
   if(x instanceof Array) return true;   // 실제 배열은 배열과 유사하다고 판단
   if(!("length" in x)) return false;   // 배열에는 length 프로퍼티가 있어야 함
   if(typeof x.length != "number") return false;   // length 는 숫자여야 함
   if(x.length < 0) return false;   // 음수가 아니어야 함
   if(x.length > 0) {
      // 배열이 비어있지 않다면, 최소한 length-1이라는 이름의 프로퍼티가 있다 
      if(!((x.length-1) in x)) return false;
   }
   return true;
}