클래스?

Parker.Park·2022년 7월 29일
0

개념

목록 보기
7/16

클래스?

대표적인 ES6에 추가된 내용중 하나인 클래스에 대해서 알아보자.
다른 언어들과의 차이점이 있다고는 하지만, JavaScript는 프로토타입 기반 객체지향 언어라고 한다. 프로토타입 기반이기 때문에 클래스가 필요없이 포로토타입 체인클로저등으로 객체 지향언어의 특징을 구현할 수 있다고 한다.

[포로토타입 체인관한 Velog]

하지만 클래스 기반 언어에 익숙한 프로그래머들에게는 혼란스러운 방식이 되었다. ES6의 클래스는 기존 프로그래머에게 빠르게 학습할 수 있도록 문법을 제시하고 있다고 한다.

이제 ES6에서의 클래스를 정리해 보자.

정의

ES6에서 클래스는 일반적으로 class 키워드를 사용하여 정의 한다.

class Animal {
  constructor(name) {
    this.name = name;
  }

  sayHello() {
    console.log(`I'm ${this.name}`);
  }
}

const cat = new Animal("nyang");
cat.sayHello(); // I'm nyang

표현식으로도 클래스를 정의할 수 있다고 하는데, 특이 케이스라고 생가하여 넘어가겠다. 필요하다면 아래 참조 사이트를 참고 바란다.

인스턴스 생성

new 연사자를 사용하여 클래스의 인스턴스를 생성할 수 있다. 이때 new는 클래스를 가리키는 것이 아닌 constructor(생성자)를 가르키는 것이라고 한다; 프로토타입 체인을 미루어 봤을때, 정의한 클래스는 생성자 함수를 포함 하고 있으며, new를 통해서 호출된 것일 것이다.

class Animal {
  constructor(name) {
    this.name = name;
  }

  sayHello() {
    console.log(`I'm ${this.name}`);
  }
}

const cat = new Animal("nyang");
console.log(cat.constructor === Animal); // true

new를 사용하지 않고는 클래스의 인스턴스를 생성할 수 없다고 한다.

const dog = Animal("ddoddo"); 
// TypeError: Class constructor Animal cannot be invoked without 'new'

constructor

constructor은 정의된 클래스의 인스턴스를 생성하고, 클래스필드를 초기화하는 메소드라고 한다.

  • 클래스에서 constructor은 1개만 존재할 수 있다.
  • constructor은 생략가능하다. 그렇기때문에 인스턴스에 프로퍼티를 추가하려면 동적으로 추가하여야한다.
  • constructor은 인스턴스를 생성과 클래스필드의 초기화를 하기때문에 초기화를 위해서라면 필수이다.
class Person {
  name = "Parker";
  sayHello() {
    console.log(`hello ${this.name}`);
  }
}

const p1 = new Person();
console.log(p1); // Person { name: 'Parker' }
p1.sayHello(); // hello Parker

//새로운 인스턴스를 생성하여도 constructor를 사용하지 않았기때문에 name property는 고정이다.
const p2 = new Person();
console.log(p2); // Person { name: 'Parker' }

기존 JavaScript에서는 constructor에서 초기화를 해주지 않으면 SyntaxError라고 하였다. 하지만 Node.js 버전 12에서 부터는 정상 동작한다고 한다. 원래는 아래 예시와 같이 초기화를 constructor안에서 해주어야 했다고 한다.

class Person {
  constructor(name = "Parker") {
    this.name = name;
  }
  sayHello() {
    console.log(`hello ${this.name}`);
  }
}

getter, setter

클래스에 대한 벨로깅한 이유는 getter, setter 파트때문이었다. 타입스크립트에 대해서 공부를 하다보니 이 부분이 부족하다고 느꼈다. (예전부터 계속 봤던것 같기하다.)

getter

getter는 클래스 필드에 접근할 때마다 클래스 필드의 값을 조작하는 행위가 있을 때마다 사용한다고 한다. getter 메소드 앞에 get 키워드를 사용하여 정의한다고 한다. 그리고 메소드 이름은 클래스 필드 이름처런 사용된다고 한다. 호출하는 것 또한 프로퍼티를 참조하는 형식으로 호출된다고 한다. getter는 반드시 무엇인가가 반환되어야 한다고 한다. 사용방법은 다음과 아래 예시와 같다.

class Num {
  constructor(arr = []) {
    this.arr = arr;
  }
  get getLast() {
    return this.arr.length === 0 ? null : this.arr[this.arr.length - 1];
  }
}

const num = new Num(["a", "b", "c"]);
console.log(num.getLast); // c

setter

setter는 클래스 필드에 값을 할당할 때마다 클래스 필드의 값을 조정하는 행위가 필요할 때 사용한다고 한다. setter 또한 getter처럼 set키워드를 사용하여 정의한다고 한다. 차이점이라면 getter가 참조하는 형식으로 호출하였다면, setter는 값을 할당하는 형식으로 메소드를 호출 한다. 예시를 보자.

class Num {
  constructor(arr = []) {
    this.arr = arr;
  }
  get getLast() {
    return this.arr.length === 0 ? null : this.arr[this.arr.length - 1];
  }

  set getLast(el) {
    this.arr[this.arr.length] = el;
  }
}

const num = new Num(["a", "b", "c"]);
console.log(num.getLast); // c

num.getLast = "z"; //setter 호출
console.log(num.getLast); // z

getter, setter는 클래스에서 새롭게 도입된 것이 아닌, 접근자 프로퍼티(accessor property)라고 한다. 그렇다 예시에서 자주 봐왔던것으로 기억한다.

클래스 상속(Class Inheritance)

클래스 상속은 코드의 재사용 관점에서 매우 유용하다고 한다.

extends 키워드

extends 키워드는 부모 클래스(base class)를 상속받은 자식 클래스(sub class)를 정의할 때 사용한다고 한다. 예시를 보자. 아래는 부모클래스를 "Rectangle"직사각형으로 자식 클래스를 "Cuboid"직육면체로 정의해 보았다.

//직사각형
class Rectangle {
  constructor(a, b) {
    //a : 가로, b : 세로
    this.a = a;
    this.b = b;
  }
  //
  sayHello() {
    console.log(`Hello`);
  }
  //직사각형의 넓이
  getArea() {
    return this.a * this.b;
  }
}

//직육면체
class Cuboid extends Rectangle {
  constructor(a, b, c) {
    //c : 높이
    super(a, b);
    this.c = c;
  }

  //직육면체 넓이 : 부모 클래스의 getArea 메소드를 "오버라이딩"한 것이다.
  getArea() {
    //직육면체 넓이 = 2 * (가로*세로 + 가로*높이 + 세로*높이)
    return 2 * (this.a * this.b + this.a * this.c + this.b * this.c);
  }

  //직육면체 부피
  getVolume() {
    return super.getArea() * this.c;
  }
}

const cuboid = new Cuboid(1, 1, 2);

cuboid.sayHello(); // Hello
//직육면체 넓이
console.log(cuboid.getArea()); // 10
//직육면체 부피
console.log(cuboid.getVolume()); // 2

console.log(cuboid instanceof Cuboid); // true
console.log(cuboid instanceof Rectangle); // true

프로토타입 체인에 의해서 "cuboid"인스턴스는 부모 클래스인 Rectagle 메소드를 사용할 수 있었던 것이다. 여기서 자식클래스인 Cuboid가 부모클래스(Rectangle)의 메소드인 "getArea"를 재정의 하였다. 이것을 Overriding(오버라이딩)이라고 한다.
개념은 다르나, 비슷한 말로는 Overloading(오버로딩)이 있는데 자바스크립에서는 지원하지 않는다고 한다. 타입스크립트에서 나오는 개념이다.

super 키워드

super 키워드는 부모 클래스를 참조할 때 또는 부모 클래스의 constructor를 호출할 때 사용한다고 한다. super 메소드는 자식 class의 constructor 내부에서 부모 클래스의 constructor를 호출한다고 한다. 부모클래스의 인스턴스를 생성한다고 한다. super를 호출하지 않으면 this에 대한 참조에러가 발생한다고 한다. 이전 예제코드에서 super을 빼서 사용하여 보자.

class Rectangle {
  constructor(a, b) {
    //가로, 세로
    this.a = a;
    this.b = b;
  }
...
}

//직육면체
class Cuboid extends Rectangle {
  constructor(a, b, c) {
    //super 사용하지 않으면 참조 에러가 발생한다.
    this.a = a;
    this.b = b;
    //높이
    this.c = c;
  }

...
}

const cuboid = new Cuboid(1, 1, 1);
/*
ReferenceError: 
Must call super constructor in derived class
before accessing 'this' or returning from derived constructor
*/

super 메소드를 호출하기 전에는 this를 참조할 수 없는 것을 의미한다고 한다. super키워드는 부모 클래스에 대한 참조라고 한다.

마치면서

아래 참조 사이트를 참조하면서 static에 관해서는 생략하였다. 위에 프로토타입 체인에 대한 내용을 알고 있다면 아래 참조사이트를 찾아가 더 많은 내용을 배울 수 있을 것이다.

참조

[클래스, PoiemaWeb, 2022년08월01일 접속]
https://poiemaweb.com/es6-class#4-%EB%A9%A4%EB%B2%84-%EB%B3%80%EC%88%98

profile
개발자준비중

0개의 댓글