본문 바로가기
D.evelop/JavaScript

[TIL]Javascript - Prototype

by Danne 2021. 8. 29.

이전에 객체지향 class 생성자 함수를 공부했다.

class를 통한 instance생성에 낭비를 개선할 수 있는 prototype
상속기능을 요상하게(?)사용할 수 있게 하는 prototype

오늘은 이 prototype에 대해서 알아보기로 했다.

 

| keywords |

 

 Prototype 

Prototype Based Lanuange

javascript는  "프로토타입 기반 객체지향 프로그래밍"이다.

 

> 함수 is 객체
> 고로 생성자 함수 is 객체
> 객체는 뭘 가진다? property!

여기서 용도가 미리 약속된 특수한 프로퍼티prototype이라고 한다.

 

 

✅prototype의 필요성

/* 생성자 함수 */
function Cat(name, color, weight){
  this.name = name;
  this.color=color;
  this.weight=weight;
  this.intro = function(){
     return this.name + "는 " + this.color + "색 이고 " + this.weight
  }
}

var coco = new Cat('코코', '노랑', '4kg');
var mimi = new Cat('미미', '회색', '2kg');

console.log(coco.intro());  // 코코는 노랑색 이고 4kg
console.log(mimi.intro());  // 미미는 회색색 이고 2kg

 

  • 위 코드에서 새로운 객체가 생성될 때마다 intro라는 함수가 새로 만들어진다.
  • 이렇게 되면 시간과 메모리가 낭비되어 성능이 저하된다.

 

🤔만약 intance들의 intro함수의 내용을 바꾸고 싶다면?

var coco = new Cat('코코', '노랑', '4kg');
coco.intro = function(){
  return "수정 : " + (this.name + "는 " + this.color + "색 이고 " + this.weight)
}

var mimi = new Cat('미미', '회색', '2kg');
mimi.intro = function(){
  return "수정 : " + (this.name + "는 " + this.color + "색 이고 " + this.weight)
}

console.log(coco.intro());  // 수정 : 코코는 노랑색 이고 4kg
console.log(mimi.intro());  // 수정 : 미미는 회색색 이고 2kg

이렇게 각 객체마다 intro 함수를 수정해줘야한다.

생성자 안에서 intro함수와 같은 메서드를 가지는 것은 생산성이 떨어진다.

 

생성자 함수Cat를 통해 나오는 객체가 공통적으로 사용할 수 있는 함수나 속성을 만들 수있다면 좋은 해결책이 될 것이다.

 

 

이런 비효율을 개선할 수 있는 방법이 prototype개념이다. 

prototype 프로퍼티로 함수를 생성하면 instance별로 함수를 생성하지 않아도 된다.

 

 

 

✅ prototype

function Cat(){}; // 이것은 객체.

var Person = new Function();  // 1번줄의 코드와 똑같은 의미. 즉 함수도 객체임.

즉 js의 함수들은 객체이기 때문에 property를 가질 수 있다.

 

예)

function Cat(name, color, weight){
  this.name = name;
  this.color=color;
  this.weight=weight;
}

 

 

 1. 

Cat 함수를 생성하면 Cat객체Cat의 prototype객체가 생성된다.

 

✔️prototype을 '유전자'라고 이해하면 비유가 쉬움

 

 

 

 2. 

Cat객체의 내부에는 prototype이라고하는 프로퍼티가 생긴다.

그 프로퍼티는 Cat의 prototype객체를 가리킨다.

Cat.prototype이라고 하면 prototype 객체를 가르키는 것.

 

 

 

 3. 

Cat의 prototype객체역시 construct라는 프로퍼티를 통해 Cat의 소속임을 표시한다.

서로간의 상호참조가 일어나는 것.

// prototype객체에 intro라는 프로퍼티를 생성한 후 함수를 정의
Cat.prototype.intro = function(){
  return this.name + "는 " + this.color + "색 이고 " + this.weight
}

// 새로운 coco객체 생성
var coco = new Cat();

console.log(coco)

 

새로운 객체 coco만 호출하면, intro는 나오지 않는다

 

 

하지만 prototype 이라는 공간에서 intro함수를 가진 다는 것을 알 수 있다.

 

 

그래서 새로운 객체 coco에 intro를 호출하면 prototype에 선언한 intro함수에 접근할 수 있다.

 

 

✨ class에 프로퍼티를 선언한 것과 차이점

∙ class생성자 함수에 직접 intro함수를 사용 : class를 통해 생성된 모든 자식 객체가 intro함수를 직접가진다.
 prototype프로퍼티를 통해 intro함수를 생성 : 부모만 intro함수를 가짐

 

 

 

 4. 

✅ __proto__

var coco = new Cat('코코', '노랑', '4kg');
var mimi = new Cat('미미', '회색', '2kg');

coco객체를 생성하면 Cat 생성자 함수를 통해 프로퍼티들이 생성된다.

그리고 Cat객체의 prototype을 가리키는 __proto__라는 프로퍼티를 볼 수 있다.

// 두 방법 모드  Cat의 prototype에 접근할 수 있다.
Cat.prototype
coco.__proto__

 

 

 5. 

coco의 프로퍼티에 없는 coco.intro를 선택하면, __proto__를 타고 올라가 뒤져 Cat객체의 prototype에서 intro를 찾아내서 사용한다.

쩜인트로군 : coco야 너 intro있니?
coco냥 : 없는데요.
쩜인트로군 : 그럼 coco 부모님 유전자 좀 확인해볼게

 

 

 

 

✅ prototpye chain

❓여기서 coco의 부모님도 intro유전자가 없으면?
   ∙ 그 부모의 부모, 그 부모의 부모, 그 부모의 부모 .... 단군 할아버지한테까지 찾아감

 

이런 연쇄적인 참조를 portotype chain이라고 한다.

 

// coco의 부모의 부모의 부모
function GrandParentsCat(){}
GrandParentsCat.prototype.myLittleBoy = 'i love you❤︎';

// coco의 부모의 부모
function ParentsCat(){}
ParentsCat.prototype = new GrandParentsCat();

// coco의 부모
function Cat(){}
Cat.prototype = new ParentsCat();

// 나는 coco
var coco = new Cat();
console.log(coco.myLittleBoy); // i love you❤︎

 

 

 

 

✅ 이제 거대한 js의 일부분이 이해되기 시작한다.

 

배열을 하나 생성해보았다.

var Array = [3, 7, 9 ,2]

Array.sort();   // 2, 3, 7, 9
Array.length;   // 4
우리가 Array라는 객체에 sort()나 length같은 함수를 추가해준 적이 있었나?
없음

 

 

배열을 new Array를 통해서 다시 만들어 보자. 

var Array = [3, 7, 9 ,2];           // 인간 방식
var Array = new Array(3, 7, 9 ,2);  // 컴퓨터 방식

 

작성 방식은 다르지만, 두 개는 똑같이 배열을 생성하게 된다.

여기서

var  변수 = new 생성자함수명();

 

어디서 많이 보지 않았나?

 

❗️결국 Array자체도 거대한 생성자 함수이다.
Array 함수 기능 : 원하는 값을 넣으면 배열로 만들어 줌.

 

우리가 메서드라 칭하는 sort()나 length같은 것을 사용할 수 있는 이유?
❗️이런 함수들이 부모 유전자(prototype)에 이미 기록되있어서

 

Array.prototype을 console에서 확인해보면 이미 만들어진 함수를 우리가 가져다 쓰는 것

 

출처 : MDN (https://developer.mozilla.org/)

 

❗️메서드를 검색할 때마다 이렇게  .prototype이 붙는 이유를 알아냄😏

 

 

이말인 즉,

Array.prototype.함수 = function(){} 이렇게 작성하면, 모든 Array자료에서 사용할 수 있는 나만의 함수를 만들수 있다는 것!

 

 

 

 

 

 

 

📚참고 자료

반응형

댓글