[JS] class vs object, 객체지향

Autumn·2020년 9월 15일
0

JavaScript

목록 보기
5/18

말로만 듣던 객체지향! 그것은 바로 class로 잘 나눠서 하는 개발이라는 뜻이었다.

  • 관련 있는 변수나 함수들을 묶어놓은 것을 class라고 한다.
  • class에는 fieldsmethods가 종합적으로 구성되어 있다.
  • 내부적으로 보여지는 변수와 밖에서 보일 수 있는 변수를 나누어서 캡슐화라고 한다.
  • 상속과 다양성이 일어날 수 있다.

    이 모든 것들이 일어나는 것이 바로 객체지향 언어


class는 '템플릿'이다. class에 데이터를 넣은 것이 바로 object




1. Class 선언하기

class Person {
  // constructor
  constructor(name, age) {
    // fields
    this.name = name;
    this.age = age;
  }
  
  // methods
  speak () {
    console.log(`${this.name}: hello!`);
  }
} // Person이라는 class는 name, age라는 fields와 speak라는 method로 이루어져 있다.

this는 '생성된 오브젝트' 라는 의미이다.

2. Object 생성하기

const ellie = new Person('ellie', 20); // 새로운 object를 만들 때 new라는 키워드를 쓴다.
console.log(ellie.name); // ellie
console.log(ellie.age); // 20
ellie.speak(); // 함수도 호출 가능. ellie: hello! 라고 출력됨

3. Getter & Setter

  • 사용자의 실수를 방어적으로 대처하는 방법!
  • get을 이용해 값을 return, set을 이용해 값을 설정할 수 있다.
    • set은 값을 설정하기 때문에 value를 받아와야 한다.

💁🏻 사용자가 나이를 -1이라고 잘못 입력하면 잘못된 값이라고 알려주는 class를 만들어보자.

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; // value가 음수면 0으로 쓰고 아니면 value 그대로 쓸래!
    // 혹은 아래와 같이 경고를 날려도 된다.
    // if (value < 0) {
    //	throw Error('age can not be negative');
    // }
  }
}

const user1 = new User('Steve', 'Jobs', -1);
console.log(user1.age); // 0 이라고 나온다.
  • call stack이 꽉 차는 것을 방지하기 위해 getter와 setter 안의 변수 이름을 조금 다르게 설정해주는데, 보통 변수 앞에_을 붙인다. (2, private 이런거 붙여도 되긴 함)
  • User라는 class에는 firstName, lastName, _age 3개의 fields가 있는 것이다.
  • 그냥 .age라고 할당하고 호출할 수 있는 것은 내부적으로 getter와 setter를 이용하기 때문이다. (??? 몬말몰)
  • get, set 바로 다음에 쓰는 age는 뭐지..? 그냥 함수 이름인가..? ➡️ 계속 등장하는 그 프로퍼티 age가 맞다.
  • 밑줄 _ 로 시작하는 프로퍼티는 객체 내부에서만 활용하고, 외부에서는 건드리지 않는 것이 관습이다.
    • 외부에서도 접근은 가능하나, 관습적으로 그렇게 하기로 했다.

4. Public field & Private field

  • public은 그냥 쓰고 private은 앞에 #을 붙이면 된다.
  • private은 class 내부에서만 보이고, 접근/변경이 가능하다.
  • 너무 최근에 추가된 것이라 아직 쓰기엔 이른 감이 있다

5. Static

  • 이것도 너무 최근에 추가됐다.
  • 오브젝트의 데이터에 상관없이 동일하게 반복적으로 사용되는 method를 정해주는 것
  • class 자체에 추가되므로 class.method 이런 식으로 써야한다. (object.method (X))
  • 메모리의 사용을 조금 더 줄여줄 수 있다.
class Article {
  static publisher = 'Dream Coding';
  constructor(articleNumber) {
    this.articleNumber = articleNumber;
  }

  static printPublisher() {
    console.log(Article.publisher);
  }
}

// 오브젝트 생성
const article1 = new Article(1);
const article2 = new Article(2);

console.log(article1.publisher); // undefined
console.log(Article.publisher); // Dream Coding
Article.printPublisher(); // Dream Coding

6. 상속(Inheritance)과 다형성(Polymorphism)

사각형, 삼각형, 원을 class로 정의하려고 한다. 세 가지 클래스는 공통적으로 높이, 넓이 값을 가지는 '도형'이다. 그래서! 반복되는 속성들을 그 때마다 계속 적는 것이 아니라, 도형(shape)을 한 번에 빡 정의한 다음에 공통적으로 쓰이는 속성 값을 재사용한다. 타이핑 할 것도 줄고 유지 보수 하기에도 좋다.

class Shape {
  constructor(width, height, color) {
    this.width = width;
    this.height = height;
    this.color = color;
  }
  
  draw() {
    console.log(`drawing ${this.color} color of`);
  }
  
  getArea() {
    return this.width * this.height;
  }
}

Shape이라는 class를 정의하였다. 이 상태에서 Rectangle이라는 class를 만들고 싶다면 반복해서 또 쓰는 것이 아니라 extends 라는 키워드를 사용해서 Shape를 연장해서 사용하면 된다.
class Rectangle extends Shape {}까지만 써도 Shape의 모든 fields와 methods가 자동으로 포함된다.

class Rectangle extends Shape {}
class Triangle extends Shape {}

const rectangle = new Rectangle(20, 20, 'blue');
const triangle = new Triangle(20, 20, 'red');

그런데, 삼각형의 면적을 구하기 위해 console.log(triangle.getArea()); 를 쓰면, 400이 출력되는데 이것은 틀린 값이다. 여기서 우리가 필요한 함수만 재정의해서 사용할 수 있다.

class Triangle extends Shape {
  getArea() {
    return (this.width * this.height) / 2;
  }
}

console.log(triangle.getArea()); // 200

draw()도 마찬가지로 재정의할 수 있는데, 재정의하면 공통적으로 정의했던 것은 아예 실행이 안 된다. 만약 공통적으로 정의한 것과 재정의한 것을 함께 쓰고 싶다면 다음과 같이 하면 된다.

class Triangle extends Shape {
  draw() {
    super.draw(); // 부모의 method 호출. drawing red color 출력됨
    console.log('🔺');
  }
  getArea() {
    return (this.width * this.height) / 2;
  }
}

(참고) instanceof

  • (왼쪽) instance of (오른쪽)
  • 왼쪽의 오브젝트가 오른쪽 클래스의 instance인지 아닌지 true/false 로 return.
profile
한 발짝씩 나아가는 중 〰 🍁 / 자잘한 기록은 아래 🏠 아이콘에 연결된 노션 페이지에 남기고 있어요 😎

0개의 댓글