클래스

모든 내용은 책을 기반으로 작성되었습니다.

자바스크립트는 프로토타입 기반 언어라서 '상속'개념이 존재하지 않는다.

클래스와 비슷하게 동작하게 흉내 내는 여러 기법들이 탄생했으며 이들 중 몇 가지는 널리 알려졌다.

ES6의 클래스에서도 일정 부분은 프로포타입을 활용하고 있다.

클래스와 인스턴스의 개념 이해

어떤 클래스의 속성을 지니는 실존하는 개체를 일컬어 인스턴스(instance)라고 한다.

프로그래밍 언어에서의 클래스는 현실세계에서의 클래스와 마찬가지로 '공통요소를 지니는 집단을 분류하기 위한 개념'이라는 측면에서는 일치하지만 인스턴스들로부터 공통점을 발견해서 클래스를 정의하는 현실과 달리, 클래스가 먼저 정의돼야만 그로부터 공통적인 요소를 지니는 개체들을 생성할 수 있다.

나아가 현실세계에서의 클래스는 추상적인 개념이지만, 프로그래밍 언어에서의 클래스는 사용하기에 따라 추상적인 대상일 수도 있고 구체적인 개체가 될 수도 있다.

자바스크립트의 클래스

프로토타입을 일반적인 의미에서의 클래스 관점에서 접근해보면 비슷하게 해석할 수 있는 요소가 없지 않다.

생성자 함수 Array를 new 연산자와 함께 호출하면 인스턴스가 생성된다. 이때 Array를 일종의 클래스라고 하면, Array의 prototype 객체 내부 요소들이 인스턴스에 '상속'된다고 볼 수 있다(엄밀히 말하면 프로토타입 체이닝).

인스턴스에 상속되는지(인스턴스가 참조하는지) 여부에 따라 **스태틱 멤버(static member)**와 **인스턴스 멤버(instance member)**로 나뉜다.

인스턴스 메서드라는 명칭은 프로토타입 메서드(prototype method)라고 부는 편이 좋다.

프로토타입 객체에 할당한 메서드는 인스턴스가 자신의 것처럼 호출할 수 있다고 했다. 이처럼 인스턴스에서 직접 호출할 수 있는 메서드가 바로 프로토타입 메서드다.

스택틱 메서드는 생성자 함수를 this로 해야만 호출할 수 있다.

ex) Rectangle.isRectangle(rect1) // static method

구체적인 인스턴스가 사용할 메서드를 정의한 '틀'의 역할을 담당하는 목적을 가질 때의 클래스는 추상적인 개념이지만, 클래스 자체를 this로 해서 직접 접근해야만 하는 스태틱 메서드를 호출할 때의 클래스는 그 자체가 하나의 개체로서 취급된다.

클래스 상속

ES5까지의 자바스크립트에는 클래스가 없습니다. ES6에서 클래스가 도입됐지만 역시나 prototype을 기반으로 한 것이다. 자바스크립트에서 클래스 상속을 구현했다는 것은 결국 프로토타입 체이닝을 잘 연결한 것으로 이해하면 된다.

[예제 7-3 / 예제 7-4]

클래스에 있는 값이 인스턴스의 동작에 영향을 줘서는 안된다. 사실 이런 형향을 줄 수 있다는 사실 자체가 이미 클래스의 추상성을 해치는 것이다. 인스턴스와의 관계에서는 구체적인 데이터를 지니지 않고 오직 인스턴스가 사용할 메서드만을 지니는 추상적인 '틀'로서만 작용하게끈 작성하지 않는다면 예기치 않은 오류가 발생할 가능성을 안고 가야한다.


하위 클래스로 삼을 생성자 함수의 prototype에 상위 클래스의 인스턴스를 부여하는 것만으로도 기본적인 메서드 상속은 가능하지만 다양한 문제가 발생할 여지가 있어 구조적 안정성이 떨어진다.

클래스가 구체적인 데이터를 지니지 않게 하는 방법

가장 쉬운 방법은 일단 만들고 나서 프로퍼티들을 일일이 지우고 도는 새로운 프로퍼티를 추가할 수 없게 하는 것이다.

다른 방법으로는 더글라스 크락포드가 제시해서 대중적으로 널리 알려진 방법으로, SubClass의 prototype에 직접 SuperClass의 인스턴스를 할당하는 대신 아무런 프로퍼티를 생성하지 않은 빈 생성자(Bridge)를 하나 더 만들어서 그 prototype이 SuperClass의 Prototype을 바라보게 한 다음, SubClass의 prototype에는 Bridge의 인스턴스를 할당하게 하는 것이다.

이렇게 하면 인스턴스를 제외한 프로토타입 체인 경로상에는 더는 구체적인 데이터가 남아있지 않게 된다.

마지막으로, ES5에서 도입된 Object.create를 이용한 방법이다.

이 방법은 SubClass의 prototype의 __proto__가 SuperClass의 prototype을 바라보되, SuperClass의 인스턴스가 되지 않으므로 위의 두 방법보다 간단하면서 안전하다.

constructor 복구하기

위 모든 방법은 상속에는 성공했지만 SubClass 인스턴스의 constructor는 여전히 SuperClass를 가리티는 상태다. 엄밀히는 SubClass 인스턴스에는 constructor가 없고, SubClass.prototype에도 없다.

프로토타입 체인상에 가장 먼저 등장하는 SuperClass.prototype의 constructor에서 가리티는 대상, 즉 SuperClass가 출력될 뿐이다.

결국 SubClass.prototype.constructor가 원래의 SubClass를 바라보도록 해주면 된다.

상위 클래스에의 접근 수단 제공

하위 클래스의 메서드에서 상위 클래스의 메서드 실행 결과를 바탕으로 추가적인 작업을 수행하고 싶을 때가 있다.

여기서 만든 방법은 SuperClass의 생성자 함수에 접근하고자 할 때는 this.super(), SuperClass의 프로토타입 메서드에 접근하고자 할 때는 this.super(propName)와 같이 사용하면 된다.

ES6의 클래스 및 클래스 상속

ES6에서는 본격적인 클래스 문법이 도입되었다.

정리

자바스크립트는 프로토타입 기반 언어라서 클래스 및 상속 개념은 존재하지 않지만 프로토타입을 기반으로 클래스와 비슷하게 동작하게끔 하는 다양한 기법들이 도입되어왔다.

클래스는 어떤 사물의 공통 속성을 모아 정의한 추상적인 개념이고, 인스턴스는 클래스의 속성을 지니는 구체적인 사례다. 상위 클래스(superclass)의 조건을 충족하면서 더욱 구체적인 조건이 추가된 것을 하위 클래스(subclass)라고 한다.

클래스의 prototype 내부에 정의된 메서드를 프로토타입 메서드라고 하며, 이들은 인스턴 스가 마치 자신의 것처럼 호출할 수 있다. 한편 클래스(생성자 함수)에 직접 정의한 메서드를 스태틱 메서드라고 하며, 이들은 인스턴스가 직접 호출할 수 없고 클래스(생성자 함수)에 의해서만 호출할 수 있다.

클래스 상속을 흉내내기 위해 세 가지 방법을 소개했다.

바로 SubClass.prototype에 SuperCLass의 인스턴스를 할당한 다음 프로퍼티를 모두 삭제하는 방법, 빈 함수(Bridge)를 활용하는 방법, Object.create를 이용하는 방법이다.

이 세 방법 모두 constructor 프로 퍼티가 원래아 생성자 함수를 바라보도록 조정해야 한다. 추가로 샹위 클래스에 접근할 수 있는 수단인 super를 구현해봤다.

여기까지 상속 및 추상화를 구현하기 위해 상당히 복잡한 방법을 사용했는데, ES6에서는 상당히 간단하게 처리되는 것을 확인했다.