개발일지

자바 스크립트 7장 클래스 본문

코어 자바스크립트 스터디

자바 스크립트 7장 클래스

박수미/ 2024. 8. 28. 22:53

7장 클래스

자바스크립트는 프로토타입 기반 언어라서 "상속"개념이 존재하지 않습니다. 따라서 ES6에서 클래스문법이 추가되었습니다.

 

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

프로그래밍 언어에서의 클래스를 다루기에 앞서 일반적인 개념부터 명확히 하고 넘어가겠습니다.

예를 들어, 어떤 가게에 다양한 음식이 한 개씩 있다고 했을 때, "음식"이라는 범주안에는 고기, 채소, 과일 등 다양한 것들이 들어갈 수 있습니다. 이들 역시 하위에 각 분류에 속하는 대상들을 나열할 수 있고, 과일 범주 아래에는 배, 사과, 바나나, 감, 오렌지 등이 포함되겠죠 여기서 가게이 있는 배, 사과, 바나나 등은 직접 만질 수 있고 볼 수 있고 먹을 수 있는 구체적이고 실존하는 사물에 해당합니다. 반면, 음식이나 과일은 어떤 사물들의 공통 속성을 모아 정의한 것일 뿐 직접 만질 수도 볼 수도 없는 추상적인 개념입니다. 한편 음식은 과일과의 관계에서 상위 개념이고, 과일은 음식과의 관계에서 하위의 개념입니다.

출처 코어 자바스크립트

위 그림과 같이 음식, 과일은 모두 집단, 즉 클래스입니다. 음식은 과일보다 상위의 개념이고, 과일은 음식보다 하위의 개념입니다. 여기서 앞의 super-, sub-을 접목해서 상위 클래스(superclass) / 하위 클래스(subclass)로 표현합니다. 그렇다면 과일 분류 하위에 또 다른 분류가 있을 경우에는 클래스 간의 관계는 어떻게 될까요?

출처 코어 자바스크립트

음식은 과일의 superclass입니다. 과일은 음식의 subclass이면서 귤류의 superclass입니다. 귤류는 과일의 subclass입니다. 하위 개념은 상위 개념을 포함하면서 더 구체적인 개념이 추가됩니다. 이처럼 클래스는 하위로 갈수록 상위 클래스의 속성을 상속하면서 더 구체적인 요건이 추가 또는 변경됩니다. 물론 하위 클래스가 아무리 구체화되더라도 이들은 결국 추상적인 개념일 뿐입니다.

 

한편 감귤, 자몽, 천혜향 등은 음식에 속해 먹을 수 있고, 과일에 속해 나무에서 열리며. 귤류에 속해 말랑한 껍질 속에 달고 신맛이 나는 과육이 들어있는 구체적인 개체들입니다. 이처럼 어떤 클래스의 속성을 지니는 실존하는 개체를 일컬어 인스턴스라고합니다.

 

현실에서는 개체들이 이미 존재하는 상태에서 이들을 구분 짓기 위해 클래스를 도입합니다. 이 때문에 하나의 개체가 같은 레벨에 있는 서로 다른 여러 클래스의 인스턴스일 수 있습니다. 예를 들어, 필자는 남성이면서 회사원이고 한국인이라는 여러 분류에 속합니다. 서로 밀접한 관련이 없는 별개의 분류체계입니다. 이미 존재하는 필자를 성질에 따라 분류해서 다양한 클래스가 생성되는 것입니다.

 

반면 프로그래밍 언어상에서는 접근 방식이 정반대입니다. 컴퓨터는 위와 같은 구분법을 알지 못하므로 사용자가 직접 여러 가지 클래스를 정의해야 하며, 클래스를 바탕으로 인스턴스를 만들 때 비로소 어떤 개체가 클래스의 속성을 지니게 됩니다. 또한 한 인스턴스는 하나의 클래스만을 바탕으로 만들어집니다. 어떤 인스턴스가 다양한 클래스에 속할 수 있지만 이 클래스들은 모두 인스턴스 입장에서는 "직계존속"입니다.

 

프로그래밍 언어에서의 클래스는 사용하기에 따라 추상적인 대상일 수도 있고 구체적인 개체가 될 수도 있습니다.

 

2. 자바스크립트의 클래스

6장에서 자바스크립트는 프로토타입 기반 언어이므로 클래스의 개념이 존재하지 않는다고 했습니다. 그렇지만 프로토타입을 일반적인 의미에서의 클래스 관점에서 접근해 보면 비슷하게 해석할 수 있는 요소가 없지 않습니다.

 

생성자 함수 Array를 new 연산자와 함께 호출하면 인스턴스가 생성됩니다. 이때 Array를 일종의 클래스라고 하면, Array의 prototype 객체 내부 요소들이 인스턴스에 "상속"된다고 볼 수 있습니다. 엄밀히는 상속이 아닌 프로토타입 체이닝에 의한 참조지만 결과적으로는 동일하게 동작하므로 이렇게 이해해도 무방합니다. 한편 Array 내부 프로퍼티들 중 prototype 프로퍼티를 제외한 나머지는 인스턴스에 상속되지 않습니다. 인스턴스가 직접 메서드를 호출할 수 있는지 여부에 따라 해당 메서드가 상속되는지 아닌지 확인해 볼 수 있습니다.

// 생성자 함수
const Rectangle = function (width, height) {
	this.width = width;
  	this.height = height;
}

// 프로토타입 메서드(prototype method)
Rectangle.prototype.getArea = function () {
	return this.width * this.height;
}

// 스태틱 메서드(static method)
Rectangle.isRectangle = function (instance) {
	return instance instanceof Rectangle && instance.width > 0 && instance.height > 0;
}

// 인스턴스 생성
const rect1 = new Rectangle(3, 4);

console.log(rect1.getArea());              // 12
console.log(rect1.isRectangle(rect1));     // Error
console.log(Rectangle.isRectangle(rect1)); // true

위 예제는 전형적인 생성자 함수와 인스턴스입니다.

생성자 함수의 prototype에 선언된 getArea() 메서드는 프로토타입 체이닝에 의해 인스턴스에 상속되고, 프로토타입 객체에 할당한 메서드는 인스턴스가 마치 자신의 것처럼 호출할 수 있습니다. 이처럼 인스턴스에서 직접 호출 할 수 있는 메서드가 바로 프로토타입 메서드입니다.

3. 클래스 상속

클래스 상속은 객체지향에서 가장 중요한 요소 중 하나입니다.

 

우리는 6장 6-2-4절에서 다중 프로토타입 체인에 대해 알아보았습니다. 아래에서 다룰 내용이 클래스 상속의 핵심입니다.

 

- Grade 생성자 함수 및 인스턴스

var Grade = function () {
	var args = Array.prototype.slice.call(arguments);
  	for (var i = 0; i < args.length; i++) {
    	this[i] = args[i];
    }
  this.length = args.length;
};

Grade.prototype = [];
var g = new Grade(100, 80);

하지만 여기까지는 세부적으로 완벽하게 superclass와 subclass의 구현이 이뤄진 것은 아닙니다.