[JavaScript] 클래스(Class)

Noma·2021년 1월 22일
0

1) Class란?

  • 객체를 생성하기 위한 템플릿으로(no data in), "특별한 함수"이다.

  • data(field)와 method를 하나로 추상화하며, 단 한 번만 선언한다.
    ( method가 없고 오직 field로만 이루어진 클래스 → data class)

  • 함수를 함수 표현식과 함수 선언으로 정의할 수 있듯이 class 문법도 class 표현식과 class 선언 두 가지 방법을 제공한다.

  • 클래스를 이용해 *캡슐화, 상속, 다형성이 일어날수 있다.

  • ES6에 추가되어졌으며, 프로토타입을 이용해서 만들어진 syntactic sugar이다.

캡슐화: 내부에서 볼 수 있는 변수와 외부에서 볼 수 있는 변수를 나누는 것

- Object

: instance of a class

클래스를 이용해 새로운 인스턴스를 생성하면 오브젝트가 된다.

클래스는 정의만 한 것이라서 실제 메모리에 올라가지 않지만, 데이터를 넣으면 오브젝트는 메모리에 올라가게 된다.

- not hoisted

함수 선언과 클래스 선언의 중요한 차이점은 함수 선언은 호이스팅이 일어나지만, 클래스 선언은 그렇지 않다.

클래스를 사용하기 위해서는 클래스를 먼저 선언해야 한다. 그렇지 않으면, 아래의 코드처럼 ReferenceError를 던진다.

const p = new Rectangle(); // ReferenceError

class Rectangle {}

2) Class declarations

class Person {
  // 🔹 constructor : 생성자
  // 생성자를 이용해 나중에 object만들 때 필요한 데이터들을 전달 받는다.
  constructor(name, age) { // 함수의 매개변수와 인자의 개념과 비슷
    // 🔹 fields
    this.name = name; // 전달받은 데이터들(인자)을 Class fields에 할당
    this.age = age;
  }
  // 🔹 methods
  speak() {
    console.log(`${this.name}: hello!`); 
  }
}

const merry = new Person("merry", 24);
console.log(merry.age); // 24
console.log(merry.name); // merry
merry.speak(); // merry: hello!

- Constructor (생성자)

: class로 생성된 객체를 생성하고 초기화하기 위한 특수한 메서드이다.

클래스 안에 한 개만 존재할 수 있다. 만약 클래스에 여러 개의 constructor 메서드가 존재하면 SyntaxError가 발생할 것이다.

3) Getter & Setter

Accessor property(접근자 프로퍼티)는 'getter(획득자)'와 ‘setter(설정자)’ 메서드로 표현된다. 객체 리터럴 안에서 getter와 setter 메서드는 getset으로 나타낼 수 있다.

class User {
  constructor(firstName, lastName, age) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.age = age;
  }
  get age() {
    // getter: obj.age을 실행할 때 실행되는 코드
    // 
    return this._age;
  }

  set age(value) {
    // setter: obj.age = value를 실행할 때 실행되는 코드
    // 
    this._age = value < 0 ? 0 : value;
  }
}
const user1 = new User("Steve", "Job", -1);
console.log(user1.age); // 0
  • getter: object.propertyName을 사용해 property를 읽으려고 할 때 실행된다.
    → 즉, 위 예제의 console.log(user1.age);처럼 필드에서 데이터를 꺼내려고 할 때 실행된다.

  • setter: object.propertyName = value으로 property에 값을 할당하려 할 때 실행된다.
    → 즉, 위 예제의 new User("Steve", "Job", -1);처럼 필드에 데이터를 넣으려고 할 때 실행된다.

  • setter를 무한 호출하지 않기 위해선 gettersetter 안에서 쓰여지는 변수의 이름을 조금 다른 것으로(e.g. age→_age) 만들어 줘야 한다.

  • 결론적으로, User라는 클래스 안에는 총 3개의 field(firstName, lastName, _age)가 있다. field에는 _age가 있지만 .age로 호출(user1.age)할 수 있는 것과 .age에 값을 할당(this.age=age;)할 수 있는 것은 gettersetter를 내부적으로 사용하기 때문이다.

❗ 참고

기술적으론 외부 코드에서 user1._age을 사용해 이름에 바로 접근할 수 있다. 그러나 밑줄 (user1._age) 로 시작하는 property는 객체 "내부"에서만 활용하고, 외부에서는 건드리지 않는 것이 관습이다. 따라서 위의 예제에서 user1.age을 통해 property에 접근하고 수정하는 것 처럼 user._name을 직접적으로 사용하지는 않는 것이 좋다.

- 사용하는 이유

일반적으로 프로그래밍을 할 때, 객체들의 데이터(필드)를 외부에서 직접적으로 접근하는 것을 막아놓는다. 필드들을 private 접근 제한자로 막아두고, 각 필드의 Getter, Setter로 접근하는 방식을 사용한다.

이렇게 프로그래밍 하는 이유는 객체의 "무결성"을 보장하기 위함이다.

예를 들어, Man이라는 클래스에 weight(몸무게)라는 필드가 존재할 때
weight는 0보다 작을 수 없으나, 외부에서 직접적으로 접근할 경우 weight에 -100이라는 값을 줌으로써 객체의 무결성이 깨지는 일이 발생한다.

이를 방지하기 위해, 필드를 private로 만들어 외부의 접근을 제한한 후
Setter를 사용해 전달받은 값을 내부에서 가공해 필드에 넣어주는 방식을 사용한다. 마찬가지로 필드 값을 가져올 때도, Getter를 사용해 본 필드의 값을 숨긴 채 내부에서 가공된 값을 꺼낼 수 있다.

출처

4) Fields (public, private)

💥 브라우저 호환성 문제가 있으므로 사용에 유의하세요.

class Experiment {
  // constructor를 쓰지 않고도 field를 생성할 수 있음
  publicField = 2;
  #privateField = 0; 
}

const experiment = new Experiment();
console.log(experiment.publicField); // 2
console.log(experiment.privateField); // undefined
  • publicField = 2;
    → 그냥 작성하면, 외부에서 접근이 가능한 public 으로 생성된다.

  • #privateField = 0;
    → 🌟 '#'을 사용하면, 클래스 내부에서만 값에 접근 및 변경이 가능한 private으로 생성된다.

5) Static properties & methods

💥 브라우저 호환성 문제가 있으므로 사용에 유의하세요.

  • class안에 있는 field와 method들은 새로운 object를 만들 때마다 값만 전달받은 인자로 변경된 채 복제되어져 만들어진다.

    하지만, object에 들어오는 데이터에 상관없이 공통적으로 class에서 쓸 수 있는 거라면 static을 이용해서 클래스 자체에만 생성하는 것이 메모리의 사용을 조금 더 줄일 수 있다.

  • static은 캐시, 고정된 설정값, 또는 인스턴스 간 복제할 필요가 없는 어떤 데이터 등에 유용하게 쓰일 수 있다.

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 (상속)

상속을 사용하면 공통된 것들을 일일히 작성하지 않아도 extends를 이용해 재사용할 수 있다.

  • extends : 클래스 선언이나 클래스 표현식에서 다른 클래스의 자식 클래스를 생성하기 위해 사용된다. (sub classing)
class Shape { 
  constructor(width, height, color) {
    this.width = width;
    this.height = height;
    this.color = color;
  }
  draw() {
    console.log(`drawing ${this.color} color of`);
  } 
  //여기서 무언가를 수정하면 Shape을 상속하는 클래스들도 변경되서 적용됨
  getArea() {
    return this.width * this.height;
  }
}

class Rectangle extends Shape {} 
// Shape에 있는 모든 것들이 Rectangle에 포함되게 됨

class Triangle extends Shape {
  // 새로운 것을 작성하면 새롭게 생성되고(여기선 toString),
  // 원래 있던 것에 다르게 작성하면 재정의 되고(여기선 getArea()),
  // 원래 있던 것을 언급하지 않고 넘어가면 그대로 복제되어 생성됨
  draw() {
    super.draw(); 
    // 부모 클래스의 draw를 호출하고 싶으면 super를 사용하면 됨
    console.log("🔺"); 
    // overriding하면 더이상 Shape에 정의된 draw함수가 호출되지 않고 재정의한 함수만 호출된다.
  }
  getArea() {
    return (this.width * this.height) / 2;
  }
  toString() {
    return `Triangle color: ${this.color}`;
  }
}

const rectangle = new Rectangle(20, 20, "blue");
rectangle.draw(); // drawing blue color of
console.log(rectangle.getArea()); // 400

const triangle = new Triangle(20, 20, "red");
triangle.draw(); // drawing red color of // 🔺
console.log(triangle.getArea()); // 200
console.log(triangle.toString()); // Triangle color: red

7) Class checking: instanceOf

object instanceof class

: object가 class를 이용해서 만들어진 instance인지 판별해주는 operator이다.
→ Boolean(T/F)을 리턴함

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
// 우리가 만든 모든 오브젝트, 클래스들은 JavaScript Object를 상속한 것임

❗ 참고 자료
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Classes
https://developer.cdn.mozilla.net/ko/docs/Web/JavaScript/Reference/Classes/Class_fields
https://www.youtube.com/channel/UC_4u-bXaba7yrRz_6x6kb_w
https://ko.javascript.info/property-accessors#ref-614
https://thiago6.tistory.com/75

profile
Frontend Web/App Engineer

0개의 댓글