Object.getPrototypeOf

이 글은 John Resig의 'Object.getPrototypeOf'을 번역한 것이다.

Object.getPrototypeOf

역사적으로 __proto__는 편리하기 때문에 많은 사랑을 받았다. __proto__는 객체의 constructor 함수의 property에 접근하는 방법이다. 사용하기 쉽지만 좀 지저분하다. 다음의 코드는 true이다:

"test".__proto__ === String.prototype
// Another alternative, not using __proto__
// Only works when constructor isn't changed
"test".constructor.prototype === String.prototype

Object.getPrototypeOf(object)은 ECMAScript 3.1 표준에 추가될 것 같다(역주, 실제로 ECMAScript 5에). 그리고 Firefox에서 이제 막 구현했다.

이제 막 표준화된 이 기능은 어떻게 사용해야 할까?

instanceOf

instanceOf를 JavaScript로 구현한다면 다음과 같다:

function instanceOf(object, constructor) {
  while (object != null) {
    if (object == constructor.prototype)
      return true;
    object = Object.getPrototypeOf(object);
  }
  return false;
}
instanceOf("test", String);
instanceOf(true, Boolean);

prototype chain을 따라서 constructor의 prototype이 있는지 찾는다. 이 코드는 getPrototypeOf을 설명하기에 좋다.

Super Methods

getPrototypeOf()를 super 키워드 처럼 사용할 수 있다. 코드를 보자:

function Person(){}
Person.prototype.kick = function(type){
  alert(type + " kick!");
}

function Norris(){}

// Inherit properties from Person
Norris.prototype = new Person();

Norris.prototype.kick = function(){
  Object.getPrototypeOf(this).kick("Roundhouse");
};

Object.getPrototypeOf(this)를 통해서 원래의 kick method에 접근 할 수 있다. 이 예제에서는 getPrototypeOf()이용하여 kick method를 override했다.

Cross-Browser Implementation

브라우저들이 Object.getPrototypeOf를 구현할 때까지 다음과 같은 코드를 사용할 수 있다:

if ( typeof Object.getPrototypeOf !== "function" ) {
  if ( typeof "test".__proto__ === "object" ) {
    Object.getPrototypeOf = function(object){
      return object.__proto__;
    };
  } else {
    Object.getPrototypeOf = function(object){
      // May break if the constructor has been tampered with
      return object.constructor.prototype;
    };
  }
}

.constuctor property는 mutable이기 때문에 이 코드는 완벽하지 않다. 사용자가 갑자기 .constructor property의 값을 바꿔 버릴 수도 있다. 그렇지만 브라우저들이 구현할때까지 충분히 쓸만할 것이다.

Why Object.getPrototypeOf?

왜 'test'.getPrototypeOf()가 아니라 Object.getPrototypeOf('test')일까? __proto__처럼 property도 아니다. 왜? 객체의 method나 property인 편이 더 편리할 것 같지만 실제로는 그렇지 않다.

일단 다음과 같은 예제부터 살펴보자:

var obj = { getPrototypeOf: "blah" };

사용자가 이렇게 정의해 버리면 getPrototypeOf()은 메소드가 아니라서 호출될 수 없다. 그러니까 개발자들은 항상 Object.getPrototypeOf()라고 사용해야 한다. getPrototypeOf()가 필요한 때는 보통 fallback같은 것을 만들 때이다. 즉, 일반적으로 필요하지 않기 때문에 모든 객채의 property일 필요는 없는 것이다.

그리고 누구도 Object의 Prototype(Object.prototype.getPrototypeOf = ...;)을 확장하는 것 같은 사악한 짓은 하지 않을 것이기 때문에 예전 코드를 지원하기도 쉽다.