Javascript

프로토타입과 클래스

하루 2022. 2. 1. 02:48

객체 생성자

객체 생성자는 함수를 통해서 새로운 객체를 만들고 그 안에 넣고 싶은 값 혹은 함수들을 구현할 수 있게 해준다.

객체 생성자를 사용할 때 보통 함수의 이름은 대문자로 시작하고, 새로운 객체를 만들 때에는 new 키워드를 앞에 붙여주어야 한다.

function Animal(type, name, sound) {
  this.type = type;
  this.name = name;
  this.sound = sound;
  this.say = function() {
    console.log(this.sound);
  };
}

const dog = new Animal('개', '멍멍이', '멍멍');
const cat = new Animal('고양이', '야옹이', '야옹');

dog.say();  // 멍멍
cat.say();  // 야옹

위 코드를 보면 dog 가 가지고 있는 say 함수와 cat 이 가지고 있는 수행하는 코드가 똑같음에도 불구하고 객체가 생성될 때 마다 함수도 새로 만들어져 this.say 로 설정 되고 있다.

같은 객체 생성자 함수를 사용하는 경우, 특정 함수 또는 값을 재사용할 수 있는데 그것이 바로 프로토타입이다.

 

프로토타입

프로토타입은 같은 객체 생성자 함수를 사용하는 경우, 특정 함수 또는 값을 재사용한다.

프로토타입은 다음과 같이 객체 생성자 함수 아래에 .prototype.[원하는키]=코드 를 입력하여 설정할 수 있다.

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

Animal.prototype.say = function() {
  console.log(this.sound);
};
Animal.prototype.sharedValue = 1;

const dog = new Animal('개', '멍멍이', '멍멍');
const cat = new Animal('고양이', '야옹이', '야옹');

dog.say();  // 멍멍
cat.say();  // 야옹

console.log(dog.sharedValue);  // 1
console.log(cat.sharedValue);  // 1
function Person(name) {
    this.name = name;
}

Person.prototype.sayHello = function () {
    console.log(`Hi! My name is ${this.name}.`);
}

const me = new Person('Jin', 99);
me.sayHello();
// Hi! My name is JIn.

 

객체 생성자 상속받기

Cat 과 Dog 라는 새로운 객체 생성자를 만든다고 가정해보자.

그리고 해당 객체 생성자들에서 Animal의 기능을 재사용한다고 가정해보자

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

Animal.prototype.say = function() {
  console.log(this.sound);
};
Animal.prototype.sharedValue = 1;

function Dog(name, sound) {
  Animal.call(this, '개', name, sound);
}
Dog.prototype = Animal.prototype;

function Cat(name, sound) {
  Animal.call(this, '고양이', name, sound);
}
Cat.prototype = Animal.prototype;

const dog = new Dog('멍멍이', '멍멍');
const cat = new Cat('야옹이', '야옹');

dog.say();
cat.say();

새로 만든 Dog와 Cat 함수에서 Animal.call을 호출해주고 있다.

여기서 첫번째 인자에는 this 를 넣어주어야 하고, 그 이후에는 Animal 객체 생성자 함수에서 필요로 하는 파라미터를 넣어주어야 한다.

(첫번째 인자의 this 는 Dog 객체를 뜻하고, 뒤에 오는 것은 파라미터 '개', name, sound 를 뜻한다.)

추가적으로 prototype 을 공유해야 하기 때문에 상속받은 객체 생성자 함수를 만들고 나서 prototype 값을 Animal prototype 으로 설정해주었다. (Dog.prototype = Animal.prototype 공유를 통해 상속)

 

클래스

클래스 기능은 C++, Java, C#, PHP 등의 다른 프로그래밍 언어에 있는 기능인데 자바스크립트에는 없었기 때문에 예전 자바스크립트(ES5)에서는 클래스 문법이 따로 없어 위에서 작성한 코드처럼 객체 생성자 함수를 사용하여 비슷한 작업을 구현해왔다.

ES6에서부터 class 문법이 추가되어서 우리가 객체 생성자로 구현했던 코드를 조금 더 명확하고, 깔끔하게 구현할 수 있게 해준다. 추가적으로 상속도 훨씬 쉽게 해줄 수 있다.

class Animal {
  constructor(type, name, sound) {
    this.type = type;
    this.name = name;
    this.sound = sound;
  }
  say() {
    console.log(this.sound);
  }
}

const dog = new Animal('개', '멍멍이', '멍멍');
const cat = new Animal('고양이', '야옹이', '야옹');

dog.say();  // 멍멍
cat.say();  // 야옹

class 에서 객체 생성자 함수와 비슷한 의미로 constructor 가 있다. constructor 는 '생성자' 라는 의미를 가지고 있다.

constructor 에 파라미터로 type, name, sound 를 받아온다.

여기서 우리가 say 라는 함수를 클래스 내부에 선언했다. 클래스 내부의 함수를 '메서드'라고 부른다.

이렇게 메서드를 만들면 자동으로 prototype 으로 등록이 된다.

 

class 를 사용했을 때에는 다른 클래스를 쉽게 상속할 수 있다.

이런식으로 클래스를 만들어서 사용하면 같은 형태를 지닌 객체들을 만들 때 객체들이 지닌 값과 함수를 보기 좋은 형태로 쉽게 관리할 수 있다. 

class A extends B;    // A는 B를 상속받는다.
super();              // 상속받은 클래스의 생성자(constructor)를 가리킨다.
class Animal {
  constructor(type, name, sound) {
    this.type = type;
    this.name = name;
    this.sound = sound;
  }
}

class Dog extends Animal {
  constructor(name, sound) {
    super('개', name, sound);	// Animal의 constructor를 가리킴
  }
}

class Cat extends Animal {
  constructor(name, sound) {
    super('고양이', name, sound);
  }
}

const dog = new Dog('멍멍이', '멍멍');
const dog2 = new Dog('왈왈이', '왈왈');
const cat = new Cat('야옹이', '야옹');
const cat2 = new Cat('냐옹이', '냐옹');

dog.say();  // 멍멍
dog2.say();  // 왈왈
cat.say();  // 야옹
cat2.say();  // 냐옹
class Food {
  constructor(name) {
    this.name = name;
    this.brands = [];
  }
  addBrand(brand) {
    this.brands.push(brand)
  }
  print() {
    console.log(`${this.name}을/를 파는 음식점들:`)
    console.log(this.brands.join(', '));
  }
}

const pizza = new Food('피자');
pizza.addBrand('피자헛');
pizza.addBrand('도미노 피자');

const chicken = new Food('치킨');
chicken.addBrand('굽네치킨');
chicken.addBrand('BBQ');

pizza.print()  // 피자을/를 파는 음식점들: 피자헛, 도미노 피자
chicken.print()  // 치킨을/를 파는 음식점들: 굽네치킨, BBQ
  • Food 라는 클래스를 생성해서 name 이라는 파라미터를 가지고 Food.nameFood.brands 라는 빈 배열을 생성한다.
  • 클래스 내부에 생성된 함수 메서드 addBrandbrand 라는 파라미터가 들어오면 Food.brands 에 배열로 추가해준다.
  • 이후 클래스 Food가 실행되면 `${Food.name}을 파는 음식점들:` 과 배열에 추가되었던 Food.brands 배열을 ',' 문자열로 합쳐서 출력하여 보여준다.