클래스는 객체 지향 프로그래밍에서 특정 객체를 생성하기 위해 변수와 메서드를 정의하는 일종의 틀로 객체를 정의하기 위한 상태와 메서드로 구성된다.
- 실무에선 사용자나 물건같이 동일한 종류의 객체를 여러 개 생성해야 하는 경우가 잦다 이럴 때 new function을 사용할 수 있는데 모던 자바스크립트에서 도입된 클래스라는 문법을 사용하면 객체지향 프로그래밍에서 사용되는 다양한 기능을 자바스크립트에서 사용할 수 있다.
기본 문법
위 예제가 class의 기본 문법이다 이렇게 클래스를 선언하고 new MyClass()를 호출하면 내부에서 정의한 메서드가 들어있는 객체가 생성된다.
객체의 기본 상태를 설정해주는 생성자 메서드 constructor()는 new에 의해 자동으로 호출되므로 특별한 절차 없이 객체를 초기화할 수 있다.
- 위 예제처럼 new User('John')을 호출하면 다음과 같은 일이 발생한다
1 새로운 객체가 생성된다.
2 넘겨 받은 인수와 함께 constructor가 자동으로 실행된다 이때 인수 'John'이 this.name에 할당된다.
- 이러한 과정을 거친 후에 user.sayHi()와 같은 객체 메서드를 호출할 수 있다.
- 이때 주의할 점은 메서드 사이에는 쉼표가 없다 만약 쉼표를 넣으면 문법 에러가 발생한다.
- 클래스와 관련된 표기법은 객체 리터럴 표기법과 차이가 있다는 점을 기억하면 좋다.
클래스란?
- 자바스크립트는 프로토타입 기반의 객체지향 언어이다 대부분의 사람들은 자바스크립트는 객체지향 프로그래밍이 아닌 함수형 프로그래밍 언어로 알고 있지만 사실 자바스크립트는 프로토타입을 기반으로 한 강력한 객체 지향 프로그래밍을 제공하기도 하는 멀티 패러다임 언어이다.
- 자바스크립트에서 클래스는 프로토타입을 이용해서 만들어졌지만 ES5의 클래스 의미와는 다른 문법과 의미를 가집니다
- 자바스크립트에서 클래스는 사실 특별한 함수이다 함수를 함수 표현식과 함수 선언으로 정의할 수 있듯이 클래스 문법도 클래스 표현식과 클래스 선언 두 가지 방법을 제공합니다.
- class User{...} 문법 구조가 진짜 하는 일은 다음과 같다
1. User라는 이름을 가진 함수를 만든다 함수 본문은 생성자 메서드에서 가져온다 생성자 메서드가 없으면 본문이 비워진 채로 함수가 만들어진다.
2 sayHi 같은 클래스 내에서 정의한 메서드를 User.prototype에 저장한다.
- new User 를 호출해 객체를 만들고 객체의 메서드를 호출하면 함수의 prototype 프로퍼티에서 설명한 것처럼 메서드를 프로토타입에서 가져온다 이러한 과정이 있어 객체에서 클래스 메서드에 접근할 수 있다.
위 그림은 class User 선언한 결과이다.
- 위 예제는 지금까지 설명했던 내용을 코드로 표현한 것이다.
클래스는 단순한 편의 문법이 아니다.
어떤 사람들은 class라는 키워드 없이도 클래스 역할을 하는 함수를 선언할 수 있기 때문에 클래스는 편의 문법에 불과하다고 이야기 한다 참고로 기능은 동일하나 기존 문법을 쉽게 읽을 수 있게 만든 문법을 편의 문법이라고 한다,.
- 위 예제처럼 순수 함수로 클래스 역할을 하는 함수를 선언하는 방법과 class 키워드를 사용하는 방법의 결과는 거의 같다 class가 단순한 편의 문법이라고 생각하는 이유가 여기에 있다.
- 하지만 두 방법에는 중요한 차이가 있다.
1 class로 만든 함수엔 특수 내부 프로퍼티인 [[FunctionKind]:"classConstructor"가 이름표처럼 붙는다.
이것만으로도 두 방법엔 분명히 차이가 있다 자바스크립트는 다양한 방법을 통해 함수에 [[FunctionKind]" : "classConstructor"가 있는지를 확인한다 이런 검증 과정이 있기 때문에 클래스를 생성자 new와 함께 호출하지 않으면 에러가 발생한다.
2 클래스 메서드는 열거할 수 없다 (non-enumerable) 클래스의 prototype 프로퍼티에 추가된 메서드 전체의 enumerable 플래그는 false 이다 for... in으로 객체를 순환할 때 메서드는 순회 대상에서 제외하고자 하는 경우가 많아 이 특징은 꽤 유용하다
3 클래스는 항상 엄격 모드로 실행된다 클래스 생성자 안 코드 전체엔 자동으로 엄격 모드가 적용된다
4 이외에도 여러 차이점이 존재하고 class를 사용하면 다양한 기능이 따라오는데 차차 다룰 예정이다.
클래스 표현식
- 위 예제는 클래스 표현식의 기본 예제이다 보시다싶이 클래스도 함수처럼 다른 표현식 내부에서 정의, 전달 반환 할당할 수 있다.
- 기면 함수 표현식과 유사하게 클래스 표현식에도 이름을 붙일 수 있다.
- 단 클래스 표현식에 이름을 붙이면 이 이름은 오직 클래스 내부에서만 사용할 수있다.
- 위 예제처럼 필요에 따라 클래스를 동적으로 생성하는 것도 가능하다.
getter와 setter
- 리터럴을 사용해 만든 객체처럼 클래스도 getter나 setter, 계산된 프로퍼티를 포함할 수 있다.
- 위 예제처럼 클래스를 선언하면 User.prototype에 getter와 setter가 만들어지므로 get과 set을 사용할 수 있다.
클래스 필드
- 다음 내용은 구식 브라우저에서는 풀리필이 필요할 수 있다.
- 지금까지 살펴본 예시에는 메서드가 하나만 있었다 클래스 필드라는 문법을 사용하면 어떤 종류의 프로퍼티도 클래스에 추가할 수 있다.
- 클래스를 정의할 때 프로퍼티 이름 = 값을 써주면 간단히 클래스 필드를 만들 수 있다.
- 이때 클래스 필드의 중요한 특징은 User.prototype이 아닌 개별 객체에만 클래스가 설정된다는 점이다.
- 또한 클래스 필드엔 복잡한 표현식이나 함수 호출 결과를 사용할 수도 있다 그리고 독립적이다.
클래스 필드로 바인딩 된 메서드 만들기
- 함수 바인딩 챕터에서 살펴본 것처럼 자바스크립트는 동적인 this를 갖는다 따라서 객체 메서드를 여기저기 전달해 전혀 다른 컨텍스트에서 호출하게 되면 this는 원래 객체를 참조하지 않는다.
- 이렇게 this의 컨텍스트를 알 수 없게 되는 문제를 잃어버린 this 라고 한다.
- 문제를 해결하기 위해 두개의 방법을 사용할 수 있다 아래 방법은 함수 바인딩에서 살펴본 것들이다.
1. setTimeout(() => button.click(), 1000) 같이 래퍼 함수를 전달하기
2 생성자 안 등에서 메서드를 객체에 바인딩하기
- 클래스 필드는 위와 같이 또 다른 this 바인딩 할 수 있는 방법이 있다.
- 여기서 click은 메서드가 아닌 클래스 필드 프로퍼티라는 것을 기억하자
- 클래스 필드 click = () => {..} 는 각 Button 객체마다 독립적인 함수를 만들고 함수의 this는 해당 객체에 바인딩 시켜준다.
따라서 개발자는 button.Click을 아무 곳에나 전달할 수 있고 this에는 항상 의도한 값이 들어간다.
- 클래스 필드의 이런 기능을 브라우저 환경에서 메서드를 이벤트 리스너로 설정해야 할 때 유용히 사용된다