class 안에는 연관있는 데이터들을 묶어놓은 field와 method가 종합적으로 묶여있는 것을 말함.
class human {
name;
age; // 이름과 나이같은 속성(field)
speak(); // speak과 같은 행동(method)
- 클래스는 청사진 또는 template이라고 불림
- 클래스 자체에는 데이터가 들어있지 않고, 틀 즉 template만 정의를 해놓고 한번만 선언한다.
- JS에선 ES6에서 class가 도입되었다
class를 이용해서 실제로 data를 넣어서 만드는 것을 object라고 한다
class를 이용해서 새로운 instance를 생성하면 object가 된다
class는 정의만 한 것이라서 실제로 메모리에 올라가진 않지만, object는 메모리에도 올라가게 된다
class human {
// constructor
constructor(name, age) {
// fields
this.name = name;
this.age = age;
}
// methods
speak() {
console.log(`${this.name}: hi!`);
}
}
const serena = new human('serena', 18); //새로운 object를 만들땐 new를 씀
console.log('serena'.name); // serena
console.log('serena'.age); // 18
serena.speak(); // serena: hi!
getter의 장점
- getter는 property를 가져올 때 데이터에 대한 작업을 수행한다
- getter는 조건을 사용하여 다른 값을 반환할 수 있다
- getter에서
this
를 사용하여 calling object의 property에 접근할 수 있다- 다른 개발자가 이해하기 쉽다
class user {
constructor(firstname, lastname, age) {
this.firstname = firstname;
this.lastname = lastname;
this.age = age;
}
}
const user1 = new user('Tom', 'brown', -1);
class user {
constructor(firstname, lastname, age) {
this.firstname = firstname;
this.lastname = lastname;
this.age = age;
}
get age() {
return this.age;
}
set age(value) {
this.age = value;
}
}
const user1 = new user('Tom', 'brown', -1);
그런데 위와 같이 하면 계속 call stack size exceeded 에러가 발생한다.
age라는 getter를 정의하는 순간, this.age는 메모리의 데이터를 읽어오는 것이 아니라, getter를 호출하게 되며, setter를 정의하는 순간, = age 는 setter를 호출하게 된다.
즉, setter 안에서 전달된 value를 this.age에 할당할 때 메모리의 값을 업데이트하는 것이 아니라 setter를 호출하면서 에러가 발생하는 것이다.
이를 방지하기 위해서 getter와 setter 안에 쓰여지는 변수 이름을 보통 _를 이용해서 바꿔준다
class user {
constructor(firstname, lastname, age) {
this.firstname = firstname;
this.lastname = lastname;
this.age = age;
}
get age() {
return this._age;
}
set age(value) {
this._age = value < 0 ? 0 : value;
}
}
const user1 = new user('Tom', 'brown', -1);
따라서 user class 내에는 firstname, lastname, _age의 3개의 field가 존재하게 됨
👉 field에는 _age지만, .age로 호출하고 값을 할당할 수 있는 것은, 내부에 getter와 setter를 이용하기 때문임
constructor를 쓰지 않고 field를 정의할 수 있다
그냥 정의하게 되면 public field, #을 붙이면 private field
class ex {
publicfield = 3;
#privatefield = 5;
}
console.log(ex.publicfield); // 3
console.log(ex.privatefield); // undefined
class 내에 있는 field와 method들은 새로운 object를 만들 때마다 그대로 복제되어 값만 지정된 값으로 변경되어 생성된다.
하지만 간혹 이런 data에 상관없이 class가 가지고 있는 고유한 값과 method가 있을 수 있는데 그런 것들은 static
이라는 키워드를 붙여 사용하면 object에 상관없이 class 자체에 연결될 수 있다.
class Article {
static publisher = 'hello';
constructor(articleNumber) {
this.articleNumber = articleNumber;
}
static printPublisher() {
console.log(Article.publisher);
}
}
const article1 = new Article(1);
const article2 = new Article(2);
console.log(Article.publisher);
Article.printPublisher();
먄약 static를 사용하지 않았다면
console.log(article1.publisher);
로 publisher를 출력할 수 있었을테지만,
static을 사용함으로써 위는 undefined로 나타난다.
왜냐하면 static은 object마다 할당되는 것이 아니라 article이라는 class 자체에 연결되어있기 때문에 class인 console.log(Article.publisher);
로 바꿔주면 'hello'가 출력됨
이처럼 static 함수를 호출할 때도 class를 이용해서
Article.printPublisher();
로 호출하면 'hello'가 출력됨
class Shape {
constructor(width, height, color) {
this.width = width;
this.height = height;
this.color = color;
}
draw() {
console.log(`drawing ${this.color} color!`);
}
getArea() {
return this.width * this.height;
}
}
위와 같이 3가지 field와 2가지 method가 존재할 때,
Rectangle이라는 클래스를 생성하고 싶을 때, extends
라는 키워드를 이용해서 shape
을 바로 연장할 수 있다.
class Rectangle extends Shape {}
이렇게만 정의를 내려도, 아래와 같이 자동으로 class shape에서 정의한 field와 method가 Rectangle에 포함이 된다
const rectangle = new Rectangle(20, 20, 'blue');
rectangle.draw(); // output: drawing blue color!
console.log(rectangle.getArea()); // 400
✔ 만약 Triangle의 getArea를 호출할 땐 '다양성'을 활용할 수 있다.
필요한 함수return (this.width * this.height)
만 바로 재정의해서 사용할 수 있으며 이를 '오버라이딩'이라고 한다.
const triangle = new Triangle(20, 20, 'red');
class Triangle extends Shape {
getArea() {
return (this.width * this.height) / 2;
}
}
console.log(triangle.getArea()); // 200;
그 외에도 Triangle에 draw를 새롭게 오버라이딩하고 싶다면
class Triangle extends Shape {
draw() {
console.log('🔺');
}
}
와 같이 작성하면 되는데, 이럴 경우 더이상 shape 내의 draw()가 호출되지 않게 된다. 만약 공통적으로 정의한 draw()도 함께 호출하고 싶다면
super.draw()
를 사용하면 된다.
class Triangle extends Shape {
super.draw();
draw() {
console.log('🔺');
}
}
triangle.draw(); // drawing red color! 🔺
왼쪽의 object가 오른쪽 class를 이용해서 만들어진 것인지 아닌지 확인하는 것
console.log(rectangle instanceof Rectangle); // True
console.log(triangle instanceof Rectangle); // False
console.log(triangle instanceof Triangle); // True
console.log(triangle instanceof Shape); // True
console.log(triangle instanceof Object); // True
🔖 object 참고
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference