Home 클래스 Class
Post
X

클래스 Class

ES6에 등장한 Class 문법에 대해 알아보자.


클래스 Class

Class객체 지향 프로그래밍에서 특정 객체를 생성하기 위해 변수와 메서드를 정의하는 일종의 틀을 말합니다.

즉, 쉽게 말하면 Class라는 특정 구조의 객체 틀을 만들어두어 동일한 종류의 객체들을 생성하는데 활용합니다.


Class 문법이 추가된 이유

클래스 방식에 익숙한 프로그래머들은 자바스크립트의 프로토타입 방식에 적응하는 것이 쉽지 않았습니다.

따라서, ES6에서는 클래스 기반 객체지향 프로그래밍 언어와 매우 흡사한 Class 문법을 추가합니다.

물론, 기존의 프로토타입 기반 객체 지향을 폐지하고 클래스 문법을 제공하는 것은 아닙니다.

제공하는 Class 문법은 하나의 함수로 엔진 내부적으로는 프로토타입 방식으로 작동합니다.


Class 정의

ES6 클래스는 class 키워드를 사용하여 정의합니다.

1
2
3
4
5
6
7
8
9
10
11
12
// 일반적으로 파스칼 케이스 사용
class Person {
  // constructor(생성자)
  constructor(name) {
    this.name = name;
  }
}

// 인스턴스 생성
const joon = new Person("joon");

console.log(joon instanceof Person); // true

이렇게 클래스를 만들고, new 연산자를 사용하여 인스턴스를 생성할 수 있습니다.


Class 선언

  • constructor

    인스턴스를 생성하고 초기화 하기 위한 특수한 메서드입니다.

    Class 안에 하나만 존재하며 constructor 내부에 선언한 클래스 필드는 클래스가 생성할 인스턴스에 바인딩 됩니다.

    클래스 필드(class field)
    클래스 내부의 캡슐화된 변수를 말합니다.
    즉, 자바스크립트의 생성자 함수에서 this에 추가한 프로퍼티

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    
    // 클래스 선언문
    class Person {
      // constructor(생성자). 이름을 바꿀 수 없다.
      constructor(name) {
        // this는 클래스가 생성할 인스턴스를 가리킨다.
        // name은 클래스 필드이다.
        this.name = name;
      }
    }
    
    // 인스턴스 생성
    const joon = new Person("joon");
    console.log(joon); // Person {name: "joon"}
    

Class 메서드 정의

프로토타입 메서드라고도 말하며 prototype 속성 내부에 정의된 메서드를 말합니다.

인스턴스의 __proto__로 연결되어 접근이 가능합니다.

메서드를 정의할 때는 객체 리터럴에서 사용하던 문법과 유사한 문법을 사용합니다.

1
2
3
4
5
6
7
8
9
10
11
12
class Calculator {
  add(x, y) {
    return x + y;
  }
  subtract(x, y) {
    return x - y;
  }
}

let calc = new Calculator();

calc.add(1, 10); // 11

정적 메서드 Static Method

정적 메서드란 랜덤값을 얻기 위해 사용하는 Math.random() 메서드처럼, 클래스의 인스턴스가 아닌 클래스 이름으로 직접 접근할 수 있는 메서드를 말합니다.

static 키워드를 메서드 이름 앞에 붙여서 사용합니다.

정적 메서드는 인스턴스에서 접근할 수 없으며 클래스로 호출해서 동작합니다.

따라서, 정적 메서드의 this는 인스턴스가 아닌 클래스를 가리킵니다.

주로 특정 클래스 인스턴스가 아닌 클래스 전체에 필요한 기능을 만들 때 사용합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Person {
  // 정적 프로퍼티
  static static_name = "static";

  // 정적 메서드
  static static_getName() {
    return this.static_name;
  }
}

const joon = new Person();

Person.static_getName(); // static

// 정적 메서드는 인스턴스로 호출할 수 없다.
joon.static_getName(); // Uncaught TypeError: foo.staticMethod is not a function

다른 정적 메서드에서의 정적 메서드 호출

위에서 정적 메서드의 this는 인스턴스가 아닌 클래스라고 말했습니다.

이를 이용해 동일 클래스 내의 다른 정적 메서드를 호출할 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Person {
  static staticMethod() {
    // 정적 메서드 내부에서의 this는 클래스 자신을 가리킨다.
    return "Static method has been called";
  }

  static anotherStaticMethod() {
    return this.staticMethod() + " from another static method";
  }
}

StaticMethodCall.staticMethod(); // 'Static method has been called'

StaticMethodCall.anotherStaticMethod(); // 'Static method has been called from another static method'

비정적 메서드에서의 호출

프로토타입 메서드에서의 this는 프로토타입 객체를 의미하므로 constructor 속성을 사용하여 접근이 가능합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
class StaticMethodCall {
  constructor() {
    console.log(StaticMethodCall.staticMethod());
    // 'static method has been called.'

    console.log(this.constructor.staticMethod());
    // 'static method has been called.'
  }

  static staticMethod() {
    return "static method has been called.";
  }
}

Protected

protected 필드는 Class 외부에서의 접근은 막고, 상속받는 객체에서 접근은 허용하는 접근 지정자입니다.

자바스크립트에서는 protected 필드를 지원하지 않아 암묵적으로 _를 앞에 붙여서 사용합니다.

_를 붙인 protected 필드에 접근하기 위해서 Getter / Setter 를 구현해서 사용합니다.

Getter는 객체의 속성 값을 반환하는 메서드이며, Setter는 객체의 속성 값을 설정, 변경하는 메서드를 말합니다.

객체 내부 속성에 직접 접근하지 않는 방법으로 코드의 안전성을 위해 사용합니다.

이전에는 get프로퍼티명()set프로퍼티명() 형식으로 메서드 이름으로 구분해서 사용했습니다.

Class 문법에서는 메서드 이름 앞에 get 또는 set을 붙여서 간단하게 구현할 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Person {
  constructor() {
    this._name = 0;
  }
  get name() {
    return this._name;
  }
  set name(newName) {
    this._name = newName;
  }
}

const joon = new Person("joon");

account.name = "jisoo";
account.name; // jisoo

Private

private 필드는 클래스 외부나 자손 클래스에서 접근을 막는 접근 지정자입니다.

#를 사용해서 선언되며 Protected의 _와 다르게 지원되는 문법입니다.

또한, private 필드는 Class 선언문 내부의 Class 생성자(Class constructor)에서 접근이 가능합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class Base {
  #privateField = "foo";
  publicField = "bar";

  #privateMethod() {
    return "baz";
  }

  publicMethod1() {
    return Base.#privateField;
  }

  publicMethod2() {
    return this.#privateField;
  }
}

const obj = new Base();

// 1. scope 밖에서 `#` 이름에 접근하는 것은 syntax error
obj.#privateField; // Uncaught SyntaxError: Private field '#privateMehtod' must be declared in an enclosing class

// 2. `private 인스턴스 메서드`는 인스턴스로부터 접근 가능합니다.
obj.#privateMethod(); // Uncaught SyntaxError: Private field '#privateMehtod' must be declared in an enclosing class
obj.publicMethod1(); // 'foo'

// 3. `this`는 예상치 못한 동작을 발생시킬 수 있습니다.
class Derived extends Base {}

console.log(Derived.publicStaticMethod1()); // foo
console.log(Derived.publicStaticMethod2()); // TypeError

상속 extends

클래스 상속 기능을 통해 클래스의 기능을 다른 클래스에서 재사용 할 수 있습니다.

extends 키워드를 사용해 부모 클래스(base class)와 상속받는 자식 클래스(sub class)를 정의합니다.

부모-자식 클래스 관계를 슈퍼-서브 클래스 관계라고도 말합니다.


super

super 키워드는 부모 클래스를 참조할 때 사용합니다.

super 키워드는 위치에 따라 다르게 동작합니다.

  • 생성자 내부

    부모 클래스의 생성자를 호출합니다.

  • 정적 메서드 내부

    부모 클래스의 static 필드를 호출합니다.

  • 인스턴스 메서드 내부

    부모 클래스의 인스턴스 속성에 접근할 수 있다.


간단 예제

부모 클래스 Parent을 상속받는 자식 클래스 Child를 정의해보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
class Base {
  constructor(a, b) {
    this.a = a;
    this.b = b;
  }

  static baseStaticField = 90;

  baseMethod() {
    return 10;
  }

  sum() {
    return this.a + this.b;
  }
}

class Extended extends Base {
  constructor(a, b, c) {
    // 생성자 내부에서의 super
    // 부모 클래스의 생성자 호출
    super(a, b);

    this.c = c;
  }

  extendedField = super.baseMethod(); // 10

  static extendedStaticField = super.baseStaticField;
  // 정적 메서드 내부에서의 super
  // 부모 클래스의 정적 필드 호출

  sum() {
    // 인스턴스 메서드 내부에서의 super
    // 부모 클래스의 인스턴스 메서드 호출
    return super.sum() + this.c;
  }
}

console.log(Extended.extendedField);
// 인스턴스 필드 선언 시 super => `undefined` 출력
//  Base 인스턴스의 자체 속성으로 정의되기 때문에 super로 호출할 수 없다.

var obj = new Extended(10, 20, 30);

document.write(obj.sum()); // 60
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.