프로토타입 기반 언어, 자바스크립트


자바스크립트는 원형 객체로 새로운 객체를 생성하는 프로토타입(원형) 기반 언어다. 프로토타입 기반 언어란 무엇일까? 자바스크립트로 프로토타입 언어의 특징을 어떻게 구현할까? 이전에 접했던 자바스크립트에서의 프로토타입에 대한 글이 어려웠다면, 이 글을 통해서 조금이나마 쉽게 이해할 수 있기를 기대한다.

프로토타입 기반 언어

자바스크립트는 프로토타입 기반 언어다. 프로토타입 기반 언어란 무엇일까? 위키피디아에는 다음과 같이 정의되어 있다.

프로토타입 기반 언어는 클래스 기반 언어에서 상속을 사용하는 것과는 다르게, 객체를 원형(프로토타입)으로 하는 복제 과정을 통해 객체의 동작 방식을 재사용 할 수 있게 한다.

image

프로토타입 기반 언어는 원형 객체를 복제하여 새로운 객체를 하는 생성하는 언어를 말한다. 그런데 자바스크립트도 복제를 하는가? 자바스크립트는 약간 다르다. 복제가 아닌 프로토타입 링크를 통해 원형을 참조한다.

그러면 프로토타입 링크란 무엇인가?

자바스크립트 객체의 프로토타입 링크

프로토타입 링크를 설명하려면, 우선 자바스크립트의 객체에 대해 먼저 알아야 한다.

자바스크립트에서 단순 원시 타입(simple primitive)인 문자열, 숫자, 불리언, null, undefined를 제외한 모든 타입은 객체다.

그렇다. 자바스크립트에서는 배열도 객체고 함수도 객체다.

자바스크립트에서 객체는 원형 객체로 부터 생성되며, 생성된 객체는 원형에 대한 프로토타입 링크(__proto__)를 갖게 된다.

__proto__는 원형에 대한 참조 정보를 갖고 있는 객체의 내부 속성으로, ES6 부터는 표준으로 제정되었다.

원형 또한 객체이기 때문에 원형은 또 다른 원형을 참조하게 되고, 다음 그림과 같이 연속된 프로토타입 링크를 통해 자바스크립트 객체의 최종 원형인 Object.prototype까지 연결된다.

프로토타입 체인

Object.prototype 객체에는 toString, hasOwnProperty 함수 등과 같이 자바스크립트 객체에서 흔히 사용하던 속성들이 정의되어 있고, 그로 인해 모든 객체에서 해당 속성들을 사용할 수 있다.

그림과 같이 객체 간에 형성되어있는 일련의 링크를 프로토타입 체인이라고 부른다.

프로토타입 체인에 대해 조금 더 알아볼 필요가 있을 것 같다.

프로토타입 체인

우선 foo라는 객체에 다음과 같이 속성을 정의한다.

객체 foo

당연한 얘기겠지만 foo.afoo.b는 2를 반환한다. 그렇다면 foo객체에 정의되지 않은 foo.c를 호출하게 되면 어떤 값을 반환할까? undefined를 반환할까?

foo객체의 프로토타입 체인을 보기 전까지 알 수 없다.

객체 foo 프로토타입 체인

이것이 foo객체의 프로토타입 체인이다. 이 체인에서 foo.c는 무엇을 반환할까?

foo객체의 속성에 접근하게 되면 프로토타입 체인은 호출한 foo객체의 속성부터 Object.prototype까지까지 프로토타입 링크를 따라 차례차례 탐색하기 시작한다. 위 그림에서는 '원형 객체2'에 c가 정의되어 있기 때문에 foo.cundefined가 아닌 7을 반환한다.

만약, 체인 상의 어떤 객체에도 존재하지 않는 foo.d에 접근하게 되면, 어떤 값을 반환할까? 프로토타입 체인의 최종 원형인 Object.prototype까지 탐색한 후 값이 없음을 확인하고 undefined를 반환한다.

자바스크립트에서는 객체 속성에 접근하게 되면 해당 객체의 속성들만 탐색한 후 결과를 반환하는 것이 아니라, 최종 원형인 Object.prototype까지 탐색한 후 결과를 반환한다는 것을 기억하자.

그러면 이제 프로토타입 체인을 코드로 직접 구현해보자.

Object.create함수로 자바스크립트의 프로토타입 체인 구현하기

ES5 이전에는 프로토타입 체인을 구현하려면 무조건 생성자 함수와 new 연산자를 사용해야 했다.

new 연산자 사용은 ES5 이전의 유일한 객체 생성 방법이며 리터럴(literal) 방식도 내부적으로는 new 연산자를 사용한다.

그러나 클래스 기반 언어를 따라 한 new 연산자는 프로토타입 체인을 복잡하게 만들어, 사용자로 하여금 프로토타입 체인에 대한 구현을 어렵게 했다.

복잡복잡

다행스럽게도 ES5부터는 Object.create라는 프로토타입 언어의 특징을 잘 살려 객체를 생성할 수 있는 새로운 방법을 제공한다.

여기서는 Object.create를 사용하여 프로토타입 체인에 대해 보다 쉽게 구현하는 방법에 대해 설명하겠다.

Object.create 함수는 ES5부터 지원하는 함수이며, 인자로 전달된 객체를 원형으로 하는 새로운 객체를 생성하는 기능을 한다.

먼저 init함수와 identify함수를 정의한 foo객체를 생성한다.

var foo = {
  init: function(who) {
    this.me = who;
  },
  identify: function() {
    return "I am " + this.me;
  }
};

코드 foo 객체

foo객체는 최종 원형 객체인 Object.prototype를 참조하고 있다.

다음으로 foo객체를 원형으로 하는 bar객체를 생성해보자.

var bar = Object.create(foo);
bar.speak = function() {
  return "Hello," + this.identify();
};

코드 bar 객체

bar 객체는 foo객체를 원형으로 생성되었기 때문에 프로토타입 링크(__proto__)를 통해 foo를 참조하고 foo에서 정의한 initidentify함수를 모두 사용할 수 있다. bar 객체에 정의한 speak함수를 보면 foo객체에서 정의한 identify함수를 사용하는 것을 볼 수 있다.

이제 마지막으로 bar를 원형으로 하는 객체를 생성해보자.

var baz = Object.create(bar);

baz.init("baz");
baz.speak(); // Hello, I am baz

코드 baz 객체

Object.create함수를 이용하여 baz 객체를 생성했다. baz의 원형 객체는 bar이며 bar의 원형 객체는 foo이기 때문에, baz에서는 fooinitbarspeak 모두 사용이 가능하다.

Object.create함수를 사용하여 자바스크립트의 프로토타입 체인을 구현해 보았다. 위에서 설명한 개념을 아주 쉽게 구현할 수 있었다.

ES5를 지원하지 않는 브라우저에서 Object.create를 사용하려면 MDN에서 제공하는 폴리필(polyfill)을 추가하면 된다.

폴리필(polyfill)이란 브라우저에서 지원하지 않는 api를 보충해 주는 코드를 말한다.

마무리

  1. 프로토타입 기반 언어인 자바스크립트의 객체는 원형으로부터 생성된다.
  2. 생성된 객체는 프로토타입 링크(__proto__)를 통해 원형을 참조한다.
  3. 객체들 사이에 형성된 일련의 링크(프로토타입 링크)를 프로토타입 체인이라고 한다.
  4. Object.create함수를 이용하면, 프로토타입 언어의 특징을 살린 프로토타입 체인을 쉽게 구현할 수 있다.




참조


김성호, FE Development Lab2016.06.03Back to list