https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Statements/class
class Fruit {
//생성자 : 필요한 데이터를 인자로 받아서 채워줌, new 키워드로 객체를 생설할 때 호출되는 함수
constructor(name, emoji) {
this.name = name
this.emoji = emoji
}
//function 키워드를 쓸수 없다.
display = () => {
console.log(`${this.name} : ${this.emoji}`)
}
}
//클래스 생성하고 사용하기
const apple = new Fruit('apple', '🍎')
console.log(apple)
apple.display()
static
재사용성 높이기 : 클래스 레벨의 메소드와 인스턴스위에서 만든 Fruit
클래스 안의 name, emoji, display메소드
는 인스턴스 레벨의 프로퍼티와 메소드라고 한다
→ 인스턴스레벨의 속성과 메소드는 반드시 생성된 인스턴스를 통해 접근해야 한다.
만약 모든 객체 마다 동일하게 참조하는 속성이나 행동은 클래스 레벨의 프로퍼티와 메소드로 만든다.
→ 클래스에 한번만 정의하고, 재사용할 수 있다.
static
키워드를 통해 클래스레벨의 프로퍼티와 메서드를 만들 수 있다.
class Fruit {
constructor(name, emoji) {
this.name = name
this.emoji = emoji
}
display = () => { //만들어진 객체에 주어진 데이터에 접근해야 한다. -> 인스턴스레벨로 둔다.
console.log(`${this.name} : ${this.emoji}`)
}
//클래스별로 공통적으로 사용할수 있고
// 만들어진 인스턴스의 데이터에 접근할 필요가 없다. -> 클래스레벨로 둔다.
static makeRandomFruit(){
//클래스 레벨의 메서드는 this를 참조할 수 없다.
return new Fruit('banana','🍌')
}
static MAX_FRUITS = 4
}
console.log(Fruit.makeRandomFruit())
Fruits.MAX_FRUITS
this
를 참조할 수 없다.클래스명 .
으로만 접근이 가능하다.Math.pow()
Number.isFinite()
등등클래스에서는 접근제어자를 이용한 캡슐화를 통해 외부에서 특정 필드에대한 접근가능여부를 결정할 수 있다.
#
키워드를 통해 name과 emoji필드를 캡슐화해준다.
class Fruit {
#name //내부에서는 사용가능, 외부에서 접근불가능
#emoji
type = '과일'
constructor(name, emoji) {
this.#name = name
this.#emoji = emoji
}
display = () => {
console.log(`${this.name} : ${this.emoji}`)
}
}
콘솔에 Fruit의 인스턴스인 apple을 찍어보면
console.log(apple)
Fruit { type: '과일', display: [Function: display] }
→ 이런식으로 #으로 캡슐화된 name, emoji 필드에 대한 정보는 감춰진다.
새로운 예시로 학생 클래스를 만들어보자
class Student {
constructor(firstName, lastName) {
this.firstName = firstName
this.lastName = lastName
}
}
여기서 학생의 이름+성을 합친 fullName
이라는 새로운 프로퍼티를 만드려면 어떻게 해야할까?
class Student {
constructor(firstName, lastName) {
this.firstName = firstName
this.lastName = lastName
this.fullName = `${this.firstName}${this.lastName}`
}
}
이 방법은 직관적으로는 가능할것 같은데..실제로 이렇게 구현하면 안된다.
그 이유는, 클래스가 생성되고 나서 → 즉, 생성자 함수가 실행되고 나면 fullName이 지정된 상태가 된다.
이후 firstName을 ‘수지’에서 ‘안나’로 변경하더라도 fullName은 여전히 ‘수지킴’이다.
그렇다면 함수를 호출하는 시점에 fullName이 만들어질 수 있도록 fullName을 만들어서 반환하는 함수를 만든다.
class Student {
constructor(firstName, lastName) {
this.firstName = firstName
this.lastName = lastName
}
**fullName() {
return `${this.firstName}${this.lastName}`
}**
}
...(클래스생성)
student.fullName()
뭔가 이상하다..!
firstName, lastName은 프로퍼티에 접근하듯이 할수있는데 → student.firstName
fullName은 함수를 호출 시켜서 접근해야 한다. → student.fullName**()**
fullName은 행동이 아니라 상태를 얻기 위한 것이므로 함수로써 정의하는 것은 무언가 이상한 느낌이 든다.
그렇다면 이 문제는 어떻게 해결할까..?
앞서 작성해둔 fullName()
함수앞에 get
키워드를 붙여서 만들수 잇다.
class Student {
constructor(firstName, lastName) {
this.firstName = firstName
this.lastName = lastName
}
**get** fullName() {
//함수지만 고정된 값이 아니라 호출시점에 데이터를 만들어서 리턴한다.
// 이는 속성에 가깝기 때문에 속성의 한부분으로 간주되는 것을 만들어야 할때
// 함수호출방식이 아닌 프로퍼티에 접근하는 것처럼 할 수 있다.
return `${this.firstName}${this.lastName}`
}
}
.fullName
으로 사용할 수 있고,class Animal {
constructor(color) {
this.color = color
}
eat() {
console.log('먹자')
}
sleep() {
console.log('잔다')
}
}
먼저 부모 클래스인 Animal을 만든다
class Tiger extends Animal {}
const tiger = new Tiger('노랑이')
console.log(tiger)
tiger.sleep()
tiger.eat()
extends
키워드를 사용하여 이 부모클래스를 상속한 Tiger클래스를 만들 수 있다.
tiger는 부모클래스에서 만들어진 프로퍼티와 메서드를 모두 사용할 수 있다.
class Dog extends Animal {
constructor(color, ownerName) {
super(color) //부모생성자를 호출해서 필요한 정보를 전달해줘야 한다.
this.ownerName = ownerName //dog 클래스에만 있는 프로퍼티
}
play() {
console.log('놀자!')
}
eat() {
//부모의 행동을 덮어씌움 -> 오버라이딩
console.log('강쥐가 먹는다.')
}
sleep() {
super.eat() //부모의 eat함수를 호출하고
console.log('강아지는 냠냠') //자식만의 고유한 기능을 추가할 수 있다.
}
}
Dog 클래스는 마찬가지로 Animal클래스를 상속한 자식 클래스이다.
ownerName
이라는 프로퍼티를 추가하려면super()
를 통해 부모클래스에서 필요한 데이터들을 먼저 전달해주어야 한다.super.eat()
처럼 부모클래스의 메소드를 호출할 수 있다.