[JavaScript] #14 - Class in Javascript
Class
class는 객체를 생성하기 위한 템플릿이다.
class를 통해 원하는 구조의 객체 틀을 짜놓고 비슷한 모양의 객체를 공장처럼 찍어낼 수 있다.
쉽게 생각해 [클래스 = 붕어빵기계 , 객체 = 붕어빵]으로 생각하면 된다.
class는 javascript에서 ES6이후에 생긴 개념으로 직관적으로 쉽게 코드를 읽을 수 있도록 만들어 줄
뿐만 아니라, 작성하기도 쉽고 class 기반 언어에 익숙한 개발자가 더 빠르게 적응할 수 있는 장점이 있다.
class
class Me {
constructor(name){
this.name = name;
}
wow(){
console.log("WOW!");
}
}
let person = new Me("Jason");
person.wow() // WOW!
class는 이런식으로 내부에서 생성자를 통해 객체가 만들어지고 해당 메서드나 프로퍼티에 객체를
통해 접근해서 사용하는 방식으로 사용된다. 클래스 내에 정의한 메서드는 해당 클래스의 프로토타입으로
정의된다.
prototype
function Me(name) {
this.name = name;
}
Me.prototype.wow = function () {
console.log("WOW!");
};
let person = new Me("Jason");
person.wow(); // WOW!
만약 생성자 함수를 통해 정의한다면 위와 같이 정의할 수 있다.
프로토타입에 대한 더 자세한 내용은
[JavaScript] - [JavaScript] #13 - Prototype
[JavaScript] #13 - Prototype
JavaScript는 프로토타입(Prototype) 기반 언어이다. JAVA와 같은 클래스(Class) 기반 객체지향 프로그래밍 언어는 사전에 미리 클래스를 정의해두고, 필요한 시점에 new 연산자와 미리 정의해둔 클래스를
yoonddo.tistory.com
class 살펴보기
class Korean {
constructor(name, age) {
this.name = name;
this.age = age;
this.country = 'Korea';
}
addAge(age) {
return this.age + age;
}
}
- 클래스 내에 정의된 함수를 method라고 부른다.
- 클래스를 통해 생성된 객체를 인스턴스(instance)라고 부른다.
- 클래스도 함수처럼 호출하기 전까지는 코드가 실행되지 않는다. 위 예제에선 단지 Korean이라는
클래스를 정의만 했을 뿐이다. new()를 사용해 호출할 수 있다. - 클래스 이름은 Korean과 같이 항상 대문자로 시작한다.
- constructor는 class에서 필요한 기초 정보를 세팅하는 곳이다. 객체를 new로 생성하면
가장 먼저 자동으로 호출된다.
- constructor() 메서드에서 name과 age 2개의 매개변수로 Korean인스턴스의
name, age 프로퍼티에 값을 할당했다.
- this는 본인 객체를 의미한다. 클래스 내에서 메서드끼리 소통하기 위해서는 this가 필요하다.
let jung = new Korean("JUNGJINYOUNG",24);
{
name: 'JUNGJINYOUNG',
age: 24,
country: 'Korea',
addAge: function(age){
return this.age + age;
}
}
Korean 클래스를 이용해 jung 객체를 만들면 위와 같은 인스턴스가 생성된다.
class 상속 - 1. extends
class Cat {
constructor(name, age) {
this.name = name;
this.age = age;
}
eat() {
return `${this.name} is eating!`
}
meow() {
return 'MEOWWWW'
}
}
class Dog {
constructor(name, age) {
this.name = name;
this.age = age;
}
eat() {
return `${this.name} is eating!`
}
bark() {
return 'WOOF'
}
}
두 개의 클래스를 보면 살짝 다르지만 여전히 복제된 기능들이 많은데 JavaScript에서 가능한 옵션 중 하나가
바로 이 복제된 코드를 Cat이나 Dog 두 클래스 모두 확장시킬 수 있는 별개의 클래스로 이동시키는 것이다.
일종의 부모와 자식 관계라고 생각하면 된다.
class Pet {
constructor(name, age) {
this.name = name;
this.age = age;
}
eat() {
return `${this.name} is eating!`
}
}
class Cat extends Pet {
meow() {
return 'MEOWWWW'
}
}
class Dog extends Pet {
bark() {
return 'WOOF'
}
}
이처럼 extend 키워드를 사용하면 자식 클래스인 Dog에서 부모 클래스인 Pet의 값을 사용할 수 있다.
let boksil = new Dog("Boksil",5);
boksil.eat() // Boksil is eating!
Dog 클래스를 살펴보면, 분명 eat 메소드와 constructor 메소드가 없는데도 eat 메소드를 사용할 수 있다.
그렇다면 Dog에도 eat 메소드를 추가해준다면?
class Dog extends Pet {
bark() {
return 'WOOF'
}
eat() {
return `${this.name} is happy!`
}
}
let boksil = new Dog("Boksil",5);
boksil.eat() // Boksil is happy!
바로 Dog 버전의 eat을 출력한다.
만약 Dog의 프로토타입에서 eat을 찾지 못하면 Pet에서 찾게 되므로 이렇게 찾아낸 것이다.
class 상속 - 2. super
부모 클래스의 값을 상속받고 추가적으로 자식만의 값을 사용하고 싶을 때 super 키워드를 사용하면 된다.
class Pet {
constructor(name, age) {
console.log('IN PET CONSTRUCTOR!')
this.name = name;
this.age = age;
}
eat() {
return `${this.name} is eating!`
}
}
class Cat extends Pet {
constructor(name, age, livesLeft = 9) {
console.log('IN CAT CONSTRUCTOR!')
super(name, age)
this.livesLeft = livesLeft;
}
meow() {
return 'MEOWWWW'
}
}
const monty = new Cat('monty',9);
// IN CAT CONSTRUCTOR!
// IN PET CONSTRUCTOR!
console.log(monty); // Cat {name: 'monty', age: 9, livesLeft: 9}
monty를 살펴보면 name이 monty이고, age는 9살에 livesLeft는 9로 설정되어 있다.
super 키워드를 사용해 부모 클래스의 constructor (Pet의 생성자)에서 온 기능을 재사용했지만, Cat에 따로 하나를 추가한 것이다.
Class를 이용한 상속
class를 이용하면 더 직관적이고 객체지향적인 상속을 구현할 수 있다.
예제
class Mammal {
constructor(name) {
this.name = name;
this.feetNum = 4;
}
move() {
console.log("움직이다");
}
eat() {
console.log("먹다");
}
}
class Cat extends Mammal {
attack() {
console.log("공격하다");
}
}
const cat1 = new Cat("야옹이");
Cat에 있는 메서드 attack, 그리고 Mammal의 메서드 move와 eat이 Prototype Chain으로 연결되어
사용될 수 있는것을 확인할 수 있다.
그 외 이런 상속법도 있다.
// 부모 클래스 Animal1을 정의한다.
function Animal1(type, name, sound) {
this.type = type;
this.name = name;
this.sound = sound;
}
// 부모 클래스의 prototype에 say() 함수를 추가한다.
Animal1.prototype.say = function() {
console.log(this.sound);
};
// 자식 클래스 Dog를 정의한다.
function Dog(name, sound) {
// 부모 클래스 Animal1을 호출해서 자식 객체를 초기화 할 데이터를 전달한다.
Animal1.call(this, '개', name, sound);
}
// 자식 클래스 Cat를 정의한다.
function Cat(name, sound) {
// 부모 클래스 Animal1을 호출해서 자식 객체를 초기화 할 데이터를 전달한다.
Animal1.call(this, '고양이', name, sound);
}
// 부모 클래스 Animal1 prototype을 자식 객체에 넣어준다. => 상속시킨다.
Dog.prototype = Animal1.prototype;
Cat.prototype = Animal1.prototype;
// 자식 클래스 객체를 생성하고 부모 클래스로 부터 상속받은 함수를 실행한다.
const dog1 = new Dog('맹맹이', '맹맹');
const cat1 = new Cat('어흥이', '어흥');
dog1.say();
cat1.say();
Overriding
일반적인 객체지향 언어처럼 생성자 오버라이딩 혹은 메서드 오버라이딩을 할 수 있다.
class Cat extends Mammal {
constructor(name, age) {
super(name);
this.age = age;
}
attack() {
console.log("공격하다");
}
move() {
console.log("날렵하게 움직이다.")
}
eat() {
super.eat();
console.log("소화하다.");
}
}
const cat1 = new Cat("야옹이", 3);
console.log(cat1);
cat1.move();
cat1.eat();
생성자 오버로딩 시에는 super를 호출해 상속받은 클래스의 속성을 가져온다.
마찬가지로 메서드 역시 super를 호출해서 상속받은 클래스의 메서드 기능을 가져올 수 있다. 만약에 메서드의 기능을 추가하는경우라면 이런식으로 사용하면 된다. eat 메서드를 참고하자.
메서드 오버라이딩을 통해 아예 기능을 변경해버릴 수도 있다. move메서드처럼 super 없이 그냥 원하는 기능을 구현해주면 된다.
자료 출처 : https://velog.io/@jinyoung985/Javascript-class%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80