본문 바로가기

Javascript/Javascript(ES6)

ES6 Class (클래스, Syntactic sugar, prototype을 이용하지만 문법적으로 예쁘게 만들어주는 class)

클래스(Class) - Syntactic sugar

문법적 설탕! 자바스크립트의 클래스(Class)다.

기존 자바스크립트 ES5 문법으로도 객체 지향 프로그래밍을 할 수 있었다. (prototype을 이용해서)

하지만 자바스크립트 문법을 배우는 사람들에게 가장 어려움을 안겨주던 것이 바로 prototype이다.

그래서 ES6에서는 java와 같은 객체 지향 프로그래밍 언어에서 사용하는 것과 유사하게 class를 사용할 수 있게 문법을 제공한다.

새로운 문법이 나온 것은 아니고 기존의 prototype으로 트랜스컴파일(?)해주는 것이다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// ES5
var Person = (function () {
  // Constructor
  function Person(name) {
    this._name = name;
  }
 
  // method
  Person.prototype.sayHi = function () {
    console.log('Hi! ' + this._name);
  };
 
  // return constructor
  return Person;
}());
 
var me = new Person('Lee');
me.sayHi(); // Hi! Lee.
 
console.log(me instanceof Person); // true


[prototype을 이용한 객체 지향 프로그래밍]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Person {
  constructor(name) {
    this._name = name;
  }
 
  sayHi() {
    console.log(`Hi! ${this._name}`);
  }
}
 
const me = new Person('Lee');
me.sayHi(); // Hi! Lee
 
console.log(me instanceof Person); // true


[ES6의 class]

다른 객체 지향 프로그래밍 문법과 똑같이 "class"라는 키워드를 사용할 수 있게 되었고 객체의 메서드도 간편하게 sayHi(){...} 이런 식으로 작성이 가능하게 되었다.

* 객체를 생성할 때는 "new"를 꼭 써야한다.

constructor(){...} , 생성자 메서드는 객체 인스턴스를 생성하고 초기화할 수 있는 특수한 메서드다.

생략가능하지만 생략하면 자동으로 빈 constructor(){} 메서드가 삽입된다.

*** 클래스의 멤버변수를 생성 및 초기화할 때는 반드시 constructor() 메서드에 작성해야 한다. 

( ex) this.name = name; ) - constructor() 메서드 외부에 변수 생성 불가.

멤버 변수는 this에 바인딩되어있으므로 항상 public 으로 외부에서 접근이 가능하다. (접근제한자 없음)

* 클래스 선언 전에 클래스를 사용하면 안된다. (ReferenceError)

- 자바스크립트에서 let, const, var, function등 모두 호이스팅이 일어나는데 class도 let, const처럼 호이스팅이 일어나지 않는 것처럼 보이기 떄문에 클래스 선언 전에 클래스를 사용하면 안된다.

Getter/Setter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Foo {
  constructor(arr = []) {
    this._arr = arr;
  }
 
  // getter는 반드시 무언가를 반환하여야 한다.
  get firstElem() {
    return this._arr.length ? this._arr[0] : null;
  }
}
 
const foo = new Foo([12]);
// 프로퍼티 firstElem에 접근하면 getter가 호출된다.
console.log(foo.firstElem); // 1
//getter 메서드는 변수처럼 foo.firstElem 으로 사용한다. foo.firstElem()아님.


[getter]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Foo {
  constructor(arr = []) {
    this._arr = arr;
  }
  //setter는 특이하게 파라미터를 한 개만 가질수 있다.
  set firstElem(elem) {
    // ...this._arr은 this._arr를 개별 요소로 분리한다
    this._arr = [elem, ...this._arr];
  }
}
 
const foo = new Foo([12]);
 
// 멤버 변수 lastElem에 값을 할당하면 setter가 호출된다.
// 마찬가지로 변수처럼 사용한다. foo.firstElem(100); 아님.
foo.firstElem = 100;
 
console.log(foo.firstElem); // 100


[setter]

public이라 외부에서 클래스의 멤버 변수에 접근이 가능한데도 이렇게 하는 것이 바람직하다.


static 메서드 

객체 인스턴스 생성없이 클래스에서 직접 호출가능한 메서드다. (인스턴스에서 호출 불가하다. 반드시 클래스에서 호출해야한다.)

애플리케이션 전역에서 사용할 유틸리티 함수를 만들 때 사용한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Foo {
  constructor(prop) {
    this.prop = prop;
  }
  static staticMethod() {
    return 'staticMethod';
  }
  prototypeMethod() {
    return 'prototypeMethod';
  }
}
 
const foo = new Foo(123);
 
console.log(Foo.staticMethod());
console.log(foo.staticMethod()); // Uncaught TypeError: foo.staticMethod is not a function



클래스 상속

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
// Base Class
class Animal {
  constructor(weight) {
    this._weight = weight;
  }
  weight() { console.log(this._weight); }
  eat() { console.log('Animal eat.'); }
}
 
// Sub Class
class Human extends Animal {
  constructor(weight, language) {
    super(weight);
    this._language = language;
  }
 
  // 부모 클래스의 eat 메소드를 오버라이드하였다
  eat() { console.log('Human eat.'); }
 
  speak() {
    console.log(`Koreans speak ${this._language}.`);
  }
}
 
const korean = new Human(70'Korean');
korean.weight(); // 70
korean.eat();    // Human eat.
korean.speak();  // Koreans speak Korean.
 
console.log(korean instanceof Human);  // true
console.log(korean instanceof Animal); // true


역시나 extends 키워드로 상속받을 수 있다.

eat()메서드는 한번 더 정의하는 것으로 오버라이드했다.

* 자바스크립트는 오버로딩을 지원하지 않는다. (arguments로 구현은 가능)

* super()

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
class Parent {
  constructor(x, y) {
    this._x = x;
    this._y = y;
  }
 
  toString() {
    return `${this._x}, ${this._y}`;
  }
}
 
class Child extends Parent {
  constructor(x, y, z) {
    // super 메소드는 자식 class의 constructor 내부에서 부모 클래스의 constructor(super-constructor)를 호출한다.
    super(x, y);
    this._z = z;
  }
 
  toString() {
    // super 키워드는 부모 클래스(Base Class)에 대한 참조이다. 부모 클래스의 프로퍼티 또는 메소드를 참조하기 위해 사용한다.
    return `${super.toString()}, ${this._z}`; // B
  }
}
 
const child = new Child(123);
console.log(child.toString()); // 1, 2, 3
cs

super는 부모클래스의 constructor메서드를 부르거나 부모클래스의 프로퍼티를 참조할 때 쓴다.

* 자식클래스의 constructor에서 super()메서드를 호출하지 않으면 에러가 남.

* super()메서드를 호출하기 전에 this 참조를 할 수 없음.


부모클래스의 정적(static)메서드도 상속됨.

마찬가지로 자식클래스의 일반 메서드에서 부모클래스의 static메서드에 접근할 수 없음.


참고 사이트

http://poiemaweb.com/es6-class