자바스크립트

Section 13. 자바스크립트 프로토타입의 개념

포칼이 2023. 4. 8. 16:25

I. 프로토타입 prototype

  • 자바스크립트는 프로토타입 기반의 객체지향 프로그래밍을 지원하는 언어

자바스크립트의 모든 객체는 Prototype을 가진다.

const obj = {};

console.log(obj);

toString이나 valueOf 같은 함수들을 그냥 가져다 쓸 수 있는 이유도 프로토타입 때문이다.

 

II. Object - 모든 객체의 조상

아래의 객체들은 모두 프로토타입을 가지고 있고 그 프로토타입들은 결국 Object 에서 파생된 것을 확인할 수 있다.

console.log(
  new String('')
);

console.log(
  []
);

console.log(
  new Map()
);

constructor 항목에서 각각의 생성자를 확인할 수 있다. 

객체 리터럴 ( {} )등의 생성자는 Object이다.

 

프로토타입 체인

특정 객체에 호출된 프로퍼티가 없다면 프로토타입을 거슬러 올라간다.

만약 Array에는 valueOf가 없지만 그 프로토타입인 Object에는 있으므로 호출이 가능하다.

III. 코드로 프로토타입에 접근하기

1. Object.getPrototypeOf

수정할 때는 __Proto__보다 이 기능을 사용하는 것이 좋다.

console.log(
  Object.getPrototypeOf({})
);

console.log(
  Object.getPrototypeOf([]) === [].__proto__
); //true

첫 번째 출력문은 다음과 같다.

2. 생성자 함수에서는 Prototype으로 프로토타입에 접근이 가능하다

즉, function 으로 선언된 함수들에서

function Person (name) {
  this.name = name;
}

// 인스턴스들에 공유될 프로토타입에 다음과 같이 접근
console.log(Person.prototype);

const hong = new Person('홍길동');

console.log(hong);

두 번째 출력문은 다음과 같다

세 번째 출력문은 다음과 같다

[[Prototype]] 이 두 단계로 있는 것을 확인 가능하다. (Person - Object)

IV. 인스턴스 vs 프로토타입 프로퍼티

function KangChicken (name, no) {
  this.name = name;
  this.no = no;
  this.introduce = function () {
    return `안녕하세요, ${this.no}호 ${this.name}점입니다!`;
  }
}

const chain1 = new KangChicken('판교', 3);

생성자 함수 KangChicken를 통해 chain1이라는 인스턴스를 생성했다.

KangChicken.prototype.introEng = function () {
  return `Welcome to Kang Chicken at ${this.name}!`;
};

console.log(chain1.introEng()); //Welcome to Kang Chicken at 판교!
console.log(new KangChicken('강남', 17).introEng()); //Welcome to Kang Chicken at 강남!

 생성자 함수에 새로운 기능을 추가했다. 그리고 인스턴스의 로그를 펼쳐보면 다음과 같다

console.log(chain1);

introduce 함수는 인스턴스가 생성될 때마다 존재한다.

introEng 함수는 프로토타입에만 존재한다. 즉, 메모리 절약이 된다.

 

메모리 사용을 최소화 하려면 다음과 같다

function KangChicken (name, no) {
  this.name = name;
  this.no = no;
}

// 공통된 요소들은 프로토타입 프로퍼티로
KangChicken.prototype.titleEng = 'KangChicken';

KangChicken.prototype.introduce = function () {
  return `안녕하세요, ${this.no}호 ${this.name}점입니다!`;
}

KangChicken.prototype.introEng = function () {
  return `Welcome to ${this.titleEng} at ${this.name}!`;
};
const chain1 = new KangChicken('판교', 3);
const chain2 = new KangChicken('강남', 17);
const chain3 = new KangChicken('제주', 24);

console.log(chain1.introduce()); //안녕하세요, 3호 판교점입니다!
console.log(chain1.introEng()); //Welcome to KangChicken at 판교!

인스턴스 레벨과 프로토타입 프로퍼티들을 비교하면 다음과 같다

console.log(chain1, chain2, chain3);

introEng 함수와 introduce 함수가 모두 프로토타입 밑에 존재하는 것을 확인할 수 있다.

 

프로토타입 레벨의 함수를 인스턴스 레벨에서 덮어쓰기가 가능하다.

const chain4 = new KangChicken('평양', 456);
chain4.introduce = function () {
  return `어서오시라요, ${this.no}호 ${this.name}점입네다!`;
}


console.log(chain4.introduce()); //어서오시라요, 456호 평양점입네다!