JavaScript Prototype

Tags: JavaScriptclassprototypeobjectinstance

July 07, 2015

JavaScript의 prototype를 처음부터 다시 공부하면서 적어보았다. C/C++와 Java로 프로그래밍을 시작했고 오래써왔기 때문에 prototype을 이해하는데 꽤 오랜시간이 걸렸다. 둘 다 상속, 캡슐화, 추상화, 다형성 등을 전부 지원하지만 접근하는 방식은 좀 다를 뿐 깊게 들어가보면 동작하는 방식은 대동소이하다. Java와 비교하면서 적었기 때문에 Java를 쓰시는 분이면 이해하기 쉬울 듯하다.

Java Class와 JavaScript Prototype

Java Class

// Java
// class declaration
class Point {
  private int x, y; // field
  
  // constructor
  public Point(int x, int y) {
    this.x = x;
    this.y = y;
  }
  
  // print method
  public void print() {
  	// print Point in "(x, y)" format
    System.out.println( "(" + this.x + ", " + this.y + ")" );
  }
}
 
// new objects
Point p1 = new Point(0, 0);
Point p2 = new Point(5, 5);

Java는 class를 설계도삼아 object를 만들어낸다. 위의 코드에서는 Point class instance인 p1, p2가 생성된다. 메모리 관점에서 봤을 때 완전히 똑같은 object 두 개가 따로 메모리 상에 저장된다.

JavaScript Prototype

// JavaScript
function Point(x, y) {
  this.x = x;
  this.y = y;
}
// Point.prototype이 자동으로 생성

Point.prototype.print = function () {
  console.log('(' + this.x + ',' + this.y +')');
}

// new instances
var p1 = new Point(0, 0);
var p2 = new Point(5, 5);

JavaScript 코드는 Java 코드와 비교하면서 한 줄 한 줄 설명해 해보았다.

Line 2 ~ 5

Java에서 class키워드를 사용해서 class를 선언하는데 비해서, JavaScript에서는 먼저 생성자(constructor)를 만든다. Point function이 선언됨과 동시에 Point function object가 생성된다 — JavaScript에서는 function도 object로 관리된다. Point function object의 내부에는 prototype이라는 property가 자동적으로 생성된다. 이게 바로 Point의 prototype이다. prototype은 메모리 상에 존재하는 object이며 거기서 생성/파생되는 모든 object의 원형이 된다. 기본으로 만들어 지는 prototype은 아무런 값이 없는 object이다 — 보든 JavaScript의 Object가 그렇듯 prototype object도 Object.prototype을 기반으로 한 object이다.

생성자Point function 에서는 일반적으로 property를 만들고 초기화하는 일을 한다. Java에서는 x, y field1 를 class 내에 따로 선언하지만 JavaScript는 따로 property1 선언은 하지 않고 생성자 내에서 this.x = x처럼 값을 넣어서 선언 및 초기화 한다. 생성자에서 추가 된 property는 prototype과는 상관없이 각 object에 종속된다.

Line 8 ~ 10

print method를 Point의 prototype에 추가한다. 이것은 Java의 print method와 같은 역할을 하게 된다. prototype에 추가 된 method와 property는 이후에 생성된 모든 instance에서 접근이 가능하다.

Line 14 ~ 15

Line 14-15에서는 new키워드로 Point instance p1, p2를 생성한다. 내부적으로 동작하는 걸 자세히 따져보면 C/C++나 Java같은 instance화 라기보다는 prototype을 가리키는 빈 object를 만드는 것에 가깝다.

p1p2는 아주 단순한 구조를 가지고 있다. 빈 object에 x, y property를 가지고 있고, 거기에 추가로 숨겨진 property인 [[Prototype]]를 가진다 — Chrome, Safari 등 많은 모던브라우저에서는 __proto__라는 이름을 사용하고 있지만 ECMAScript 표준은 [[Prototype]]이다.

두 instance의 [[Prototype]]은 모두 Person.prototype를 가리킨다. 간단히 말해, p1p2는 하나의 prototype object를 공유한다. 이렇게 prototype object를 공유함으로써 Prototype Chain과 Property Shadowing이 가능해진다.

JavaScript prototypePoint.prototypep1p2x:0, y:0x:5, y:5print function


[1]: Java에서는 field, JavaScript에서는 property