반응형

우선 이 포스트는 http://insanehong.kr/post/javascript-prototype/#toc_291 를 읽고

나름 정리와 추가코드를 작성한 것임을 미리 밝히고 시작하겠습니다.

그래서 해당 블로그의 글을 읽고 오시면 더 도움이 되실것 같습니다.


SF만화나 영화를 보면 프로토타입이란 단어가 간혹 들린다. 예를 들자면 어떤 사이보그들의 모체 혹은 처음 버전을 프로토타입이라고

얘기를 하는데, 자바스크립트에서의 프로토타입도 이와 크게 다르지 않다.

자바스크립트에서의 프로토타입은 객체생성의 모체가 되는 놈을 말한다.

여기까지는 대부분 아는데, 이 프로토타입에는 2가지 유형이 있다는 것을 대부분은 모르고 있다.

프로토타입에는 프로토타입 연결과 프로토타입 속성 2가지가 있다.

이때, 흔히 API나 책에서 정의 내리고 있는 프로토타입은 프로토타입 연결인데,

우리가 활용하고 작성하는 코드들은 프로토타입 속성을 이용한 것이다.

아래와 같은 코드를 chrome 개발자도구의 console에 입력해보자

 function Member(){
	this.x = "this";
};
Member.prototype.x = "protoX";
Member.prototype.y = "protoY";
Member.x = "x";

var a = new Member();
console.log(a.x);

실행을 하기전에 결과를 생각해보자.


자 생각해보자 기존에 우리는 prototype을 변경하면 해당 객체로 생성된 모든 하위객체들이 영향을 받는다고 알고 있었다.

그결과로 a.y에는 정상적으로 protoY가 출력됨을 확인할 수 있다.

그렇다면 Member.prototype.x 의 값을 protoX로 변경했으니 a.x 에도 protoX가 들어있어야 하지 않나?? 

하지만 결과는 this이다.

여기서 개발자도구의 watch Expressions로 각각 속성값들이 어떻게 할당되어있는지 확인해보겠다.


a의 속성에는 x와 _proto_ 2가지가 있음을 알 수 있다.

a의 _proto_는 어디에서 나온것일까? 추가적으로 Member의 속성도 확인해보겠다.

Member의 속성을 보면 특이한 점을 발견할 수 있다.

Member의 x라는 속성은 x라는 값을 가지고 있다. 

a와 동일한 x값을 가지고 있지 않다. 

또하나, prototype 이란 속성과 _proto_ 라는 속성 2가지가 있다는 점이다.

두 속성의 하위 속성들을 보면 a의 _proto_ 와 동일한 속성을 가진 놈을 찾을 수 있다.

바로  prototype 속성이다.

위 과정들을 보며 탁하고 감이 오는가?

a는 Member로 직접 객체생성이 된 것이 아니라, Member의 prototype 이란 속성으로 객체생성이 되었다는 것이다.

여기에서 Member.prototype을 프로토타입속성

a._proto_ 를 프로토타입 연결 이라고 한다.

즉, 자바스크립트에서는 최초 객체생성시 원형 객체의 prototype에 있는 원형의 복사본을 통해서 객체를 생성하는데,

이로인해 하위 객체들은 원형 객체인 Member의 영향을 받지 않고, 원형의 prototype 에 영향을 받게 되는 것이다.

응? 그렇다면 prototype.x = "protoX" 는 왜 동작하지 않는가? 라고 의문을 가질수도 있다.

이것은 자바스크립트 상속에 관한 개념인데,

자바스크립트에서는 해당 객체에 없는 속성은 자신의 _proto_로 계속해서 올라가면서 찾는다.

이로인해, y의 경우 a에 없는 속성이기에 a 의 _proto_인 Member.prototype 에게서 찾아낸 것이고,

x의 경우에는 a에게 있기에 prototype의 x를 쓰지 않은 것이다.


자 정리해보자.

자바스크립트객체에는 프로토타입 속성과 프로토타입 연결 2가지속성이 있는데,

프로토타입 속성이 흔히 우리가 사용하는 프로토타입이며, 이는 선언된 객체의 복사본이다.

프로토타입 연결은 생성된 객체의 원형을 나타내는 속성이다.

prototype에 속성을 추가한다고 하여 무조건 모든 하위 객체에 영향을 주는 것은 아니다.

상속개념으로 인해 하위 객체가 prototype에 추가된 속성과 동일한 이름을 가지고 있을 경우,

하위 객체가 가지고 있는 속성을 먼저 본다.

그리고 하위객체에 해당 속성이 없다면 하위객체의 모체로 찾아가서 속성을 할당받는다.


사용법만 익히면 될것같은 자바스크립트가 갈수록 너무너무 재밌어 진다.

다음 포스트에도 좀 더 개념적으로, 좋은코드로 정리해야겠다. 



출처: http://jojoldu.tistory.com/7?category=635878 [기억보단 기록을]



[Javascript ] 프로토타입 이해하기

자바스크립트는 프로토타입 기반 언어라고 불립니다. 자바스크립트 개발을 하면 빠질 수 없는 것이 프로토타입인데요. 프로토타입이 거의 자바스크립트 그 자체이기때문에 이해하는 것이 어렵고 개념도 복잡합니다.

하지만 프로토타입이 무엇인지 깨우친 순간 자바스크립트가 재밌어지고, 숙련도가 올라가는 느낌을 팍팍 받을 수 있습니다. 그럼 지금부터 프로토타입을 이해해봅시다.

Prototype vs Class

클래스(Class)라는 것을 한 번쯤은 들어보셨을겁니다. Java, Python, Ruby등 객체지향언어에서 빠질 수 없는 개념이죠. 그런데 중요한 점은 자바스크립트도 객체지향언어라는 것입니다. 이게 왜 중요하냐구요? 자바스크립트에는 클래스라는 개념이 없거든요. 대신 프로토타입(Prototype)이라는 것이 존재합니다. 자바스크립트가 프로토타입 기반 언어라고 불리는 이유이죠.

클래스가 없으니 기본적으로 상속기능도 없습니다. 그래서 보통 프로토타입을 기반으로 상속을 흉내내도록 구현해 사용합니다.

참고로 최근의 ECMA6 표준에서는 Class 문법이 추가되었습니다. 하지만 문법이 추가되었다는 것이지, 자바스크립트가 클래스 기반으로 바뀌었다는 것은 아닙니다.


어디다 쓰나요?

그럼 프로토타입을 언제 쓰는지 알아봅시다.

넌 이미 알고있다

자바스크립트에 클래스는 없지만 함수(function)와 new를 통해 클래스를 비스무리하게 흉내낼 수 있습니다.

function Person() {
this.eyes = 2;
this.nose = 1;
}
var kim  = new Person();
var park = new Person();
console.log(kim.eyes);  // => 2
console.log(kim.nose); // => 1
console.log(park.eyes); // => 2
console.log(park.nose); // => 1

kim과 park은 eyes와 nose를 공통적으로 가지고 있는데, 메모리에는 eyes와 nose가 두 개씩 총 4개 할당됩니다. 객체를100개 만들면 200개의 변수가 메모리에 할당되겠죠?
바로 이런 문제를 프로토타입으로 해결할 수 있습니다.

function Person() {}
Person.prototype.eyes = 2;
Person.prototype.nose = 1;
var kim  = new Person();
var park = new Person():
console.log(kim.eyes); // => 2
...

자바스크립트 개발을 하시는 분이라면 아마 써보진 않았어도 최소한 본 적은 있을겁니다. 간단히 설명하자면 Person.prototype이라는 빈 Object가 어딘가에 존재하고, Person 함수로부터 생성된 객체(kim, park)들은 어딘가에 존재하는 Object에 들어있는 값을 모두 갖다쓸 수 있습니다.
즉, eyes와 nose를 어딘가에 있는 빈 공간에 넣어놓고 kim과 park이 공유해서 사용하는 것이죠. 이해되셨나요?

프로토타입을 깊게 파보면 엄청나게 복잡하지만 개발자가 사용하는 부분만 본다면 이게 거의 전부입니다. 하지만 개발자는 사용법만 알고있는게 아니라 언제나 왜? 를 생각해야합니다.

프로토타입이 왜 이렇게 쓰이는지 조금 더 깊게 알아보도록 하겠습니다.


Prototype Link와 Prototype Object

자바스크립트에는 Prototype Link 와 Prototype Object라는 것이 존재합니다. 그리고 이 둘을 통틀어 Prototype이라고 부릅니다. 프로토타입을 좀 안다는 것은 이 둘을 완벽히 이해하고 갖고 놀 수준이 되었다는 뜻입니다.

제가 프로토타입에 대해 공부하면서 중요하다고 생각되는 포인트가 몇 가지 있었습니다. 그 포인트들을 잘 이해하면서 보시기 바랍니다.

Prototype Object

모든 객체(Object)의 조상은 함수(Function)입니다.

function Person() {} // => 함수
var personObject = new Person(); // => 함수로 객체를 생성

personObject 객체는 Person이라는 함수로부터 파생된 객체입니다. 이렇듯 언제나 객체는 함수로부터 시작됩니다. 여러분이 많이 쓰는 일반적인 객체 생성도 예외는 아닙니다.

var obj = {};

얼핏보면 함수랑 전혀 상관없는 코드로 보이지만 위 코드는 사실 다음 코드와 같습니다.

var obj = new Object();

위 코드에서 Object가 자바스크립트에서 기본적으로 제공하는 함수입니다.

Object도 함수다!

Object와 마찬가지로 Function, Array도 모두 함수로 정의되어 있습니다. 이것이 첫 번째 포인트입니다.

그렇다면 이것이 Prototype Object랑 무슨 상관이있느냐? 함수가 정의될 때는 2가지 일이 동시에 이루어집니다.

1.해당 함수에 Constructor(생성자) 자격 부여

Constructor 자격이 부여되면 new를 통해 객체를 만들어 낼 수 있게 됩니다. 이것이 함수만 new 키워드를 사용할 수 있는 이유입니다.

constructor가 아니면 new를 사용할 수 없다!

2.해당 함수의 Prototype Object 생성 및 연결

함수를 정의하면 함수만 생성되는 것이 아니라 Prototype Object도 같이 생성이 됩니다.

함수를 정의하면 이렇게 됩니다

그리고 생성된 함수는 prototype이라는 속성을 통해 Prototype Object에 접근할 수 있습니다. Prototype Object는 일반적인 객체와 같으며 기본적인 속성으로 constructor와 __proto__를 가지고 있습니다.

prototype 속성으로 Prototype Object에 접근

constructor는 Prototype Object와 같이 생성되었던 함수를 가리키고 있습니다.
__proto__는 Prototype Link입니다. 밑에서 자세히 설명합니다.

이제 위에서 kim과 park이 나왔던 예제를 다시 보겠습니다.

function Person() {}
Person.prototype.eyes = 2;
Person.prototype.nose = 1;
var kim  = new Person();
var park = new Person():
console.log(kim.eyes); // => 2
...

이제 왜 Person.prototype을 사용하는지 눈에 보이시나요?

Person.prototype 객체에 eyes와 nose 속성이 추가되었다!

Prototype Object는 일반적인 객체이므로 속성을 마음대로 추가/삭제 할 수 있습니다. kim과 park은 Person 함수를 통해 생성되었으니 Person.prototype을 참조할 수 있게 됩니다.

Prototype Link를 보기 전에 Prototype Object를 어느 정도 이해하시고 보기 바랍니다. 함수가 정의될 때 이루어지는 일들을 이해하는 것이 두 번째 포인트, Prototype Object를 이해하는 것이 세 번째 포인트입니다.


Prototype Link

kim 객체는 eyes가 없는데 ??

kim에는 eyes라는 속성이 없는데도 kim.eyes를 실행하면 2라는 값을 참조하는 것을 볼 수 있습니다. 위에서 설명했듯이 Prototype Object에 존재하는 eyes 속성을 참조한 것인데요, 이게 어떻게 가능한걸까요??

바로 kim이 가지고 있는 딱 하나의 속성 __proto__가 그것을 가능하게 해주는 열쇠입니다.

prototype 속성은 함수만 가지고 있던 것과는 달리(Person.prototype 기억나시죠?) 
__proto__속성은 모든 객체가 빠짐없이 가지고 있는 속성입니다.

__proto__는 객체가 생성될 때 조상이었던 함수의 Prototype Object를 가리킵니다. kim객체는 Person함수로부터 생성되었으니 Person 함수의 Prototype Object를 가리키고 있는 것이죠.

드디어 __proto__를 공개합니다

__proto__를 까보니 역시 Person 함수의 Prototype Object를 가리키고 있었습니다.

객체, 함수, Prototype Object의 관계

kim객체가 eyes를 직접 가지고 있지 않기 때문에 eyes 속성을 찾을 때 까지 상위 프로토타입을 탐색합니다. 최상위인 Object의 Prototype Object까지 도달했는데도 못찾았을 경우 undefined를 리턴합니다. 이렇게 __proto__속성을 통해 상위 프로토타입과 연결되어있는 형태를 프로토타입 체인(Chain)이라고 합니다.

프로토타입 체인, 최상위는 Object

이런 프로토타입 체인 구조 때문에 모든 객체는 Object의 자식이라고 불리고, Object Prototype Object에 있는 모든 속성을 사용할 수 있습니다. 한 가지 예를 들면 toString함수가 있겠습니다.

Object속성인 toString함수를 kim도 사용가능

__proto__와 프로토타입 체인을 이해하는 것이 네 번째 포인트입니다.



출처 : https://medium.com/@bluesh55/javascript-prototype-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0-f8e67c286b67

반응형

+ Recent posts