프로토 타입 prototype

김수연·2022년 9월 19일
0

자료구조 / 알고리즘

목록 보기
14/16
post-thumbnail

📌 Prototype vs Class

자바스크립트는 본래 클래스라는 개념이 없었다   -> 상속 개념 없음

대신 프로토타입이 존재한다.   -> 상속 개념을 흉내

최근 class가 추가 되었지만 자바스크립트는 여전히 프로토타입 기반이다.

📌 왜 있는 걸까?

function Person() {
  this.job = true;
  this.age = 23;
}

var kim  = new Person();
var park = new Person();

console.log(kim.job);  // => true
console.log(kim.age);  // => 23
console.log(park.job); // => true
console.log(park.age); // => 23

kim, park은 모두 동일한 값을 가지고 있지만 메모리에는 각각 두개씩 4번 할당된다

이런 중복 할당을 해결하는게 프로토타입이다.

function Person() {}

Person.prototype.job = true;
Person.prototype.age = 23;

var kim  = new Person();
var park = new Person():

console.log(kim.age); // => 23
...

Person.prototype이라는 빈 Object가 어딘가에 존재하고, Person 함수로부터 생성된 객체들은(kim, park) 어딘가에 존재하는 Object에 들어있는 값을 모두 갖다쓸 수 있다.

즉 kim, park이 같은 공간을 공유하는 개념이다.


자바스크립트에는 Prototype Link 와 Prototype Object가 존재하고 이 둘을 통틀어 Prototype이라고 부른다.

📌 Prototype Object

객체는 언제나 '함수'로 생성된다.

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

일반적인 객체 생성도 마찬가지다

var obj = {};

위의 객체 생성 역시 아래의 방법으로 생성된다. Object 함수는 자바스크립트에서 기본으로 제공된다.

var obj = new Object();

Object와 마찬가지로 Function, Array도 모두 함수로 정의되어 있다. 그런데 이게 Prototype Object와 무슨 관련이 있을까?

# 생성자 자격 (constructor) 부여

  • 함수가 정의될 때 2가지 일이 동시에 일어나는데 그 중 하나가 생성자 자격이다.

  • 생성자 자격이 부여되면 new를 통해 객체를 만들 수 있게 된다.
    (함수만이 new 키워드 사용가능한 이유!)

obj 는 Object(생성자) 함수로 만들어진 객체일 뿐
함수가 아니기 때문에 new 키워드로 객체를 만들 수 없음

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

드디어 Prototype Object가 등장했다'

  • 생성자 자격 부여와 동시에 Prototype Object가 생성되고

  • 각각 prototype과 constructor으로 서로에게 접근 할 수 있다.

  • 이때 생성된 Prototype 객체는 일반 객체와 같다


위에서의 예시를 다시 살펴보자

function Person() {} 

Person.prototype.job = true;
Person.prototype.age = 23;

var kim  = new Person();
var park = new Person():

console.log(kim.age); // => 23
...

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

🚨 그런데 어떻게 참조할 수 있는걸까?
(나의 속마음: 아무리 kim,park이 Person함수로 생성됐다지만
kim.Person.prototype.age 가 아니라 kim.age 로 값을 바로 불러 올 수 있을까?)


  • Person 함수가 가진 prototype 속성은 함수만 가질 수 있다면
    Person Prototype Object가 가진 __proto__는 모든 객체가 가진 속성이다.

  • __proto__는 객체가 생성될 때 조상이었던 함수의 Prototype Object를 가리킨다. (예시에선 Person Prototype Object을 가리킴)

  • 이때 kim객체는 eyes를 직접 가지고 있지 않기 때문에 eyes 속성을 찾을 때 까지 상위 프로토타입을 탐색한다.

  • 이렇게 __proto__속성을 통해 상위 프로토타입과 연결되어있는 형태를 프로토타입 체인(Chain)이라고 한다.

  • 최상위인 Object의 Prototype Object까지 도달했는데도 못찾았을 경우 undefined를 리턴한다.

이런 프로토타입 체인 구조 때문에 모든 객체는 Object의 자식이라고 불리고, Object Prototype Object에 있는 모든 속성을 사용할 수 있다.


📌 프로토타입 확장

1. 객체 속성, 메서드 정의

function Animal (name, sound){
	this.name = name;
	this.sound = sound;
}

Animal.prototype.getInfo = function(){
	return this.name + '가(이)' + this.sound + ' 소리를 냅니다.';
}

2. 생성자 함수 생성

function Friends(name, sound){
	Animal.call(this, name, sound);
}

이때 call() 함수의 첫번째 매개변수는 다른 곳에서 정의된 함수를 현재 컨텍스트에서 실행할 수 있도록 한다.

  • 즉 이미 생성된 Animal 함수를 현재 Friends 함수의 컨텍스트에서 실행할 수 있다.

3. 문제 발생

const dog = new Friends('개', '멍멍');
const cat = new Friends('고양이', '냥');
 
console.log(dog.getInfo()); // getInfo() is not a function
console.log(cat.getInfo()); // getInfo() is not a function

그런데 왜 getInfo 메서드를 사용할 수 없을까?

const isEmptyFriends = Object.getOwnPropertyNames(Friends.prototype);
const isEmptyAnimal = Object.getOwnPropertyNames(Animal.prototype);

console.log(isEmptyFriends); // [ 'constructor' ]
console.log(isEmptyAnimal); // [ 'constructor', 'getInfo' ]

확인 결과 Friends의 프로토타입 객체는 기본 constructor 속성 말고는
Animal 프로토타입 객체의 메서드를 상속 받지 못한 것 을 볼 수 있다.
(constructor 속성 덕분에 기본 Animal 속성은 접근 가능)

4. 문제 해결

1 ) Object.create로 Animal의 프로토타입 객체를 Friends의 프로토타입 객체로 설정한다.

Friends.prototype = Object.create(Animal.prototype);

console.log(Friends.prototype.constructor); // Animal

2 ) 생성자 속성을 Friends로 바꾸기

Friends.prototype.constructor = Friends;
  • 프로토타입을 Animal.prototype으로 설정 했기 때문에 기본 constructor 속성값이 Animal이다.
  • 이 값을 Friends로 바꿔주면 Animal 메서드까지 완벽하게 상속 받게 된다.

6. 완성

function Animal (name, sound){
	this.name = name;
	this.sound = sound;
}

Animal.prototype.getInfo = function(){
	return this.name + '가(이)' + this.sound + ' 소리를 냅니다.';
}

function Friends(name, sound){
	Animal.call(this, name, sound);
}
																						
Friends.prototype = Object.create(Animal.prototype);

Friends.prototype.constructor = Friends;

const dog = new Friends('개', '멍멍');
const cat = new Friends('고양이', '냥');

console.log(dog.getInfo()); // 개가(이)멍멍 소리를 냅니다.
console.log(cat.getInfo()); // 고양이가(이)냥 소리를 냅니다.

출처
오승환 - [Javascript ] 프로토타입 이해하기 👀 (클릭!)

profile
길을 찾고 싶은 코린이 of 코린이

0개의 댓글