본문으로 바로가기

[JavaScript (8)] Javascript prototype chain(프로토타입 체인)

category 3. 웹개발/3_2_1 Javascript 2020. 3. 25. 16:30
반응형

[JavaScript (8)] Javascript prototype chain(프로토타입 체인)

안녕하세요. 갓대희 입니다. 이번 포스팅은 [ 자바스크립트 프로토타입 체인 입니다. : ) 

 

0. 들어가기 앞서

 

Java, C++ 등: 클래스 기반 객체지향 프로그래밍 언어
Javascript : 프로토타입 기반 객체지향 프로그래밍 언어

Java : 객체 생성 이전에 클래스를 정의하고 이를 통해 객체(인스턴스)를 생성한다.
Javascript : 클래스 없이(Class-less)도 객체를 생성할 수 있다.
 물론 ECMAScript 6에서 클래스가 추가 되었다. 하지만 자바스크립트는 여전히 클래스를 기반으로 하진 않는다.

위에서 정의한 것과 같이 Javascript는 자바스크립트는 클래스라는 개념이 없다.
그래서 기존의 객체를 복사해서 새로운 객체를 생성하는데 이와 같은 개념을 프로토타입 기반의 언어 라고 보면 된다.
이제부터 그럼 프로토타입(Prototype)에 대해 알아 보도록 하자.

 

1. Prototype

 - Prototype : 원형, 시제품, 견본
 - 프로토타입 상속(prototypal inheritance) : Prototype을 통해 확장과 객체의 재사용이 가능하다.

▶ 1. Object

 - 먼저 간단하게 객체를하나 생성 해보자.

ex)

var goddaehee = new Object();
goddaehee.name = 'goddaehee';
goddaehee.age = 19;

console.log(goddaehee.toString()); //[object Object]

 - 분명 객체를 만들때에는 toString이라는 함수를 생성하지 않았지만 toString()함수를 사용 가능하다.
 - 이 원리를 살펴보기 위해 goddaehee 객체를 살펴보자.

 - 추후 알게 되겠지만, __proto__ : Object => Object를 상속 받아 Object의 메서드인 toString()을 사용할 수 있었다. 이 부분을 조금 더 정확히 알아보자.

 

1) _proto__
 - 모든 객체는 [[Prototype]]이라는 인터널 슬롯(internal slot)를 가진다.
 - __proto__ : goddaehee라는 객체를 만들어내기 위해 사용된 객체 원형에 대한 숨겨진 연결 이라고 볼 수 있다. (즉 Object를 상속 받았다.)
              ECMAScript의 스펙으로는 [[Prototype]] 이고, 크롬, 파이어 폭스 등의 브라우저는 __proto__로 노출 하고 있다.
 - 해당 함수를 통해 [[Prototype]]에 접근 가능하다.
 - 생성된 객체가 자신의 원본 객체에 접근할 수 있는 프로퍼티가 바로 __proto__ 프로퍼티이다.
ex)

Object.getPrototypeOf(goddaehee);
console.log(goddaehee.__proto__ === Person.prototype); // true

2) constructor 프로퍼티
 - 프로토타입 객체는 constructor 프로퍼티를 갖는다.
 - 객체의 입장에서 자신을 생성한 객체를 가리킨다.
 - 생성된 객체는 자신을 만들 때 어떤 생성자 함수가 호출되었는지 확인 할 수 있다.
 - 즉 goddaehee객체의 프로토타입 객체는 Object.prototype, Object() 생성자 함수를 가리킨다.
 - goddaehee 객체를 생성한 객체는 Object() 생성자 함수이다.
ex)

console.log(goddaehee.constructor === Object); // true

▶ 2. 함수

 - 위에서 객체를 생성하여 간단하게 프로토 타입을 살펴 보았는데, 이번엔 함수를 생성해보도록 하자.
 - 우리가 흔히 사용해왔던 Javascript의 재사용 예제를 먼저 살펴 보겠다.

ex) 재사용을 하지 않은 경우

var goddaehee = {
	'name' : 'goddaehee'
	, 'age' : 19
	, 'hand' : 2
}

var younghee = {
	'name' : 'younghee'
	, 'age' : 17
	, 'hand' : 2
}

ex) 재사용 case

function Person(name, age){
	this.hand = 2;
	this.name = name;
	this.age = age;
}

var goddaehee = new Person('goddaehee', 19);
var younghee = new Person('younghee', 17);

 

1) 함수의 prototype 확인
 - 최상위 객체인 Object의 prototype을 살펴 본 것처럼 함수의 prototype도 살펴보고 비교 해보자.

함수 Person이 갖고 있던 prototype 프로퍼티를 그대로 "goddaehee"가 갖고 있는 것을 볼 수 있다.


 - prototype : 함수만 갖을 수 있는 프로퍼티. 함수의 프로토타입 객체를 프로토타입 프로퍼티(Prototype Property)라고 한다.
 - __proto__ : Object와 함수 모두 갖고 있는 속성. __proto__속성은 결국 Object를 가리킨다.

 - 함수 및 객체 생성 순서
① Javascript에서 함수가 정의 될 때, 함수는 기본적으로 Constructor(생성자)가 부여된다.
  new를 통해서 객체를 생성할 수 있게된다. (ex. var goddaehee = new Person('goddaehee', 19);)
② goddaehee객체는 Person객체가 할당되어 
  name, age 속성만 goddaehee, 19로 변경 되었고 구조는 Person 객체의 구조를 상속받아 Person의 모든 속성을 사용할 수 있다.
③ 즉, 객체 및 함수는 내부 __proto__ 프로퍼티를 통해 상위 객체로 연결(ex Person.prototype과 연결)하여 접근이 가능 하다. 이를 프로토 타입 체이닝이라고 한다.

 

2) 속성
 - Object.prototype.constructor : 객체의 프로토타입을 생성하는 함수.
ex)

console.log(Person.prototype.constructor);
console.log(goddahee.prototype.constructor); // 에러 발생, 함수만 prototype 프로퍼티를 가질 수 있다.


 - Object.prototype.__proto__ : 객체가 초기화될 때 프로토타입으로 사용된 객체를 가리 킨다.
ex) getPrototypeOf함수를 통해 접근해보자.

Object.getPrototypeOf(Person); 
Object.getPrototypeOf(goddaehee);

 - 결국 위의 예제는 다음과 같은 도식과 같은 구조라고 볼 수 있다.

3) this
 - 함수 생성시 this를 사용한 예제를 살펴 보았다. 이를 사용할 수 있는 이유는 다음과 같은 과정이 생략 되어있다고 보면된다.
function Person(){
    //var this = {}; // this가 자동으로 생성 되어 __proto__ 프로토타입 객체를 참조 한다.

    //return this; this를 반환한다.
}

▶ 3. 프로토타입 체인(prototype chain)

 - 프로토타입이 상위 프로토타입까지 연결되는 구조를 말한다.
 - 즉, 하위 프로토타입은 상위 프로토타입의 속성과 메소드를 공유 받는다.

 - 모든 객체(String, Array 등등)는 위에서 설명한 프로토타입 기반 방식으로 정의, 생성 된다.
 - 모든 객체들은 Object 함수의 프로토타입인 Object.prototype을 시작으로 복제 된다.
 
 - __proto__를 통해 goddaehee의 조상을 찾아 가보자.

ex)

function Person(name, age){
	this.hand = 2;
	this.name = name;
	this.age = age;
}

var goddaehee = new Person('goddaehee', 19);

var firstParent = goddaehee.__proto__;
console.log(firstParent); // constructor: f Person(name, age)

var secondParent = firstParent.__proto__;
console.log(secondParent); // constructor: f Object();

var thirdParent = secondParent.__proto__;
console.log(thirdParent); // null

 - 위에서 살펴 본 것 처럼 모든 객체의 부모 객체인 Object.prototype에서 프로토타입 체인은 끝나게 된다.  즉 최상위 객체는 Object이다.

▶ 4. 프로토타입 확장

 - 프로토타입도 결국 객체이기 때문에 프로퍼티를 추가 하거나 삭제할 수 있다.
 - 프로토타입에 프로퍼티, 메소드를 추가/삭제 할때는 객체에 추가/삭제할 때와는 다른 방법을 사용한다.
ex)

function Person(name, age){
	this.hand = 2;
	this.name = name;
	this.age = age;
}

var goddaehee = new Person('goddaehee', 19);
var younghee = new Person('younghee', 17);

// 프로퍼티 추가
Person.prototype.foot = 2;

// 메소드 추가
Person.prototype.getName = function(){
	return this.name;
}

goddaehee.getName(); // goddaehee => 프로토타입 체인으로 연결되어 있기 떄문에 goddaehee객체에서도 사용 가능.

 

▶ 5. 정리

 - 자바스크립트는 프로토타입 기반의 언어이므로 프로토타입을 사용하여 객체지향 설계가 가능하다. 물론 Class가 ES6 부터 도입되었지만, 자바스크립트가 Class 기반의 언어는 아니다.

 - 모든 함수는 prototype이라는 프로퍼티가 있다.
 - 생성자 함수를 통해 만든 객체는 속성 __proto__를 통해 함수 객체의 프로토타입으로 연결된다. 프로토 타입 체이닝의 개념

 - 모든 객체의 최상위 프로토타입은 Object의 prototype 객체이다.

반응형

댓글을 달아 주세요