JavaScript

[JavaScript] #14 - Class in Javascript

yoonddo 2023. 1. 20. 10:57

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