요새 한창 javascript 작업을 해서, prototype 을 이용한 OOP programming 을 많이 하고 있다. 그런데 기본적으로 inheritance(상속)이 되지 않아서 편법(?) 을 사용하고 있는데 여기서 prototype 궁금 해져서 살펴보게 됐다.
이 부분을 몰라도 programming 하는 데에는 전혀 지장이 없다. 그냥 개인적인 호기심과 code 에 대한 이해도 향상을 위한 삽질일 뿐이다. 물론 이런 이해가 좋은 coding 을 하는데에 도움이 될 수는 있다고 생각하지만, 오히려 생각이 많아져 코딩이 느려지는 단점이 될 수도 있다.^^
먼저 설명을 위해서 용어에 대한 정의를 설명하도록 하자.
object 란?
먼저 여기서 이야기하는 object 의 개념을 조금 명확히 하자. javascript 에서 object 라 함은 일반적인 primitive type 이외의 모든 것들이 object type 이라 이녀석들을 object 라고 한다.[ref. 2] java 등에서 이야기하는 class 의 instance 를 object 라고 부르는 것과 조금 다르게 primitive type 이외의 모든 type 을 object 라고 부른다고 이해하자.__proto__
__proto__ 는 예전에 사용하던 이름이다. 이 녀석을 ECMA 에서는 Prototype 이라고 부른다. 그리고 접근(access) 하는 방법도a.__proto__가 아니라 아래같은 함수를 이용하도록 하고 있다.
Object.getPrototypeOf(a)여하튼 이 글에서는 혼동을 피하기 위해 __proto__ 라는 이름을 사용하도록 하겠다.
prototype
javascript 에서 prototype 이라는 이름의 member(property) 를 가지는 녀석은 함수(function)뿐이다.[ref. 2] 이 prototype 을 위의 __proto__ 와 구분지어서 "prototype property" 라고 부른다. 그러나 여기서는 그냥 __proto__ 와 prototype 으로 구분지어 이야기할 것이다.Java class VS Javascript function
이제 __proto__ 와 prototype 의 차이를 알아보자. 이 __proto__ 와 prototype 의 차이를 이해하기 위해서 여기서는 우리가 기존에 알고 있는 Java 같은 OOP 언어의 관점에서 설명을 하도록 하겠다.
function A(){ ... } // 이 때 a 는 함수이기에 prototype 을 갖게 된다. A.prototype -> A {} A.__proto__ -> function Empty() {} var aa = new A() -> undefined aa.__proto__ -> A {} aa.__proto__ == A.prototype -> true A.prototype.m1 = function() {...} aa.m1()
이것을 java 의 class 와 비교해 보자. class A 가 new 되면(instantiate) 그 reference 인 aa 는 class 의 member variable 들을 property 로 가지게 된다.
class A{ public int b; public A(){ this.b = 3; } public void m1(){ System.out.println("m1"); } } A aa = new A(); System.out.println(aa.b);
prototype
그런데 javascript 에는 java 같은 oop 에서 사용하는 class 가 없다. 물론 javascript 의 object 를 이용해서 단순히 member 변수나 method 들을 가질 수 있다. 하지만 상속(inheritance) 등의 개념을 사용할 수는 없다. 그래서 prototype 이 필요하다. 이 prototype 에 member 들을 전부 넣어놓고는 inheritance 처럼 다른 object 에 member 들을 전달할 일이 있을 때 이 prototype 만을 넘겨주면 되도록 하였다. 이런식으로 oop 의 inheritance 가 가능하도록 해주는 것이다.(물론 다른 이점들도 있겠지만...^^)그래서 function 이라는 object 에는 prototype 이라는 member 변수(property) 가 무조건 생기게 하였다. 약간의 추측이 들어간 글이지만, ref. 4 의 prototype 의 정의를 봐도 알 수 있듯이 이 prototype 의 목적은 member(property 라고도 부르는) 를 공유하기 위한 목적이다. 그리고 ref. 5 를 참고하면 좀 더 명확해 질 듯 하다. ref.2 에서 보면 이런 것을 prototypical inheritance mechanism 이라 부르는 듯 하다.
prototype 의 장점
이런 prototype 의 장점은 ref.2 에서도 확인할 수 있듯이 확장성이 좋다. 우리는 이 prototype 에 원하는 member 를 쉽게 추가할 수 있다. 굳이 상속을 안해도 기존에 존재하는 object 에 원하는 기능을 추가할 수 있게 된다.A.prototype.mynewmethod = function(){ ... } var a = new A() a.mynewmethod()이런 식으로 A 에 새로운 method 를 손쉽게 추가해서 사용할 수 있다.
Java 같은 class 에서는 class 를 직접 수정하지 않는이상 그 class 에 새로운 함수를 넣을 수 없지만, javascript 에서는 가능하다. prototype 을 직접 접근할 수 있기 때문이기도 하고, prototype 안의 method 를 찾아서 호출해 주기 때문이기도 하다.
이런 것을 mixin 이라 한다.
constructor
원래 oop language 에서는 new 를 하면 constructor 가 호출이 된다. 이런 기능을 javascript 에서 해주기 위해 new 를 할 때 constructor 라는 이름의 member(property) 를 추가해 주게 된다.var a = new A()javascript 에서 new 를 하게 되면 아래와 같은 일을 하게 된다.[ref. 3]
- 새로운 object a 를 만들고
- 만들어진 object a 의 constructor 변수(property) 를 만들고 이 constructor 변수에 function A 를 set 한다.
a.constructor = A; // javascript code
- a.__proto__ 을 만들고 a.__proto__ 에 A.prototype(constructor 의 prototype) 을 할당한다.
a.__proto__ = A.prototype; // javascript code
- 그리고는 constructor 를 호출한다.
__proto__ , prototype
이제 위에서 설명한 이 둘의 차이를 정리해 보자.__proto__ 는
- var a = new A() 처럼, new 로 instantiate 할 때 생겨나는 변수다.
- 여기에 constructor 의 prototype 인 A.prototype 을 할당하게 된다.
prototype 은
- function A(){...} 처럼 함수를 정의할 때 만들어 지는 변수다.
- 이 곳에 oop 의 member 에 해당하는 녀석들을 assign 하면 된다.
- 상속처럼 한 class 의 member 들을 그대로 가져오려 할 때 이 prototype 을 복사 해 오면 된다.
함수 정의 function declaration
우리가 아래처럼 함수를 정의(declaration) 하게 되면 Declaration Binding 할 때 함수가 instantiation 된다.function Test() {}
- Source code is parsed
- -> JavaScript program is evaluated
- -> The global execution context is initialized
- -> declaration binding instantiation is performed
References
- var functionName = function() {} vs function functionName() {}
- Understanding JavaScript Prototypes.
- JavaScript constructors, prototypes, and the `new` keyword
- Annotated ECMAScript 5.1 > 4.3 Definitions
- ECMA-262-3 in detail. Chapter 7.2. OOP: ECMAScript implementation
댓글 없음:
댓글 쓰기