ES6 이전의 자바스크립트는 프로토타입 기반언어로 '상속', 클래스라는 개념이 없었다. 사용자의 필요에 따라 결국 생겨나게 되었지만, 여전히 프로토타입을 일정부분 활용하기 때문에 클래스 자체의 활용법 외에 클래스를 흉내내던 ES5 방식도 학습하는 것도 중요하다.
01. 클래스와 인스턴스의 개념 이해
객체지향 언어에서는 반드시 클래스라는 개념이 등장한다.
클래스는 '계급, 집합, 집단' 뜻의 영단어로, 프로그래밍 언어 내에서도 동일한 뜻으로 사용된다.
클래스는 공통 요소를 지니는 집단을 분류하기 위한 개념
나는 이를 일종의 '카테고리'라고 이해했다.
하나의 예시를 들어 설명하자면,
'음식'이라는 범주 내에는 '과일, 고기, 채소' 라는 요소가 들어가고, 이들 또한 하나의 범주로 과일은 '사과, 오렌지, 배' 라는 요소를 가진다.
음식, 과일, 사과 이 세가지를 놓고보면 상·하위 개념이 존재한다.
이를 그림으로 표시하면 아래와 같다.
그림 7-1
'과일', '음식'은 개체가 속할 수 있는 집단, 클래스이다.
'사과'는 '과일'의 하위개념이고 '과일'은 '음식'의 하위 개념이다. (subordinate > sub)
반대로 '음식'은 '과일'의 상위개념이고, '과일'은 '사과'의 상위개념이다. (superior > super)
클래스는 또 다른 클래스의 범주에 속할 수 있고, 이런 관계에서 상위에 있는 클래스를 상위클래스(superclass), 하위에 있는 클래스를 하위클래스(subclass)로 표현한다.
그림 7-2
클래스는 클래스 내부로 들어갈수록, 즉 하위클래스일수록 좀 더 구체적인 개념이 추가된다.
위 그림을 예시로 들면 아래와 같다.
- 음식 : 먹을 수 있음
- 과일 : 먹을 수 있음, 나무에서 열매가 열림
- 귤류 : 먹을 수 있음, 나무에서 열매가 열림, 말랑한 껍집 속에 달고 신 과육이 들어있음
이처럼 클래스는 하위로 갈수록 상위의 개념들을 상속받으며 더 구체적인 개념이 추가 혹은 변경된다.
하지만 클래스는 아무리 구체화되도 결국 추상적인 개념이며, 개체가 될 수 없다. 일종의 설계도나 카테고리일 뿐이다.
반면 '귤, 자몽, 천헤향' 등은 클래스를 통해 만들어진 실존하는 개체이다. 이와 같이 어떤 클래스의 속성을 지닌 실존하는 개체를 인스턴스라고 한다.
인스턴스는 '사례'라는 뜻을 가지며, 풀어 해석하면 '어떤 조건에 부합하는 구체적인 예시'이다.
여기서 조건은 '클래스'이며 클래스에 속한 개체는 '조건을 만족하는 예시', 즉 인스턴스가 된다.
현실에서는 실존하는 개체들을 분류하기 위해 클래스를 만들어내지만, 프로그래밍 언어에서는 반대이다.
사용자가 직접 클래스를 만들어 속성을 정의하고, 이를 통해 인스턴스를 만들어야만 그 개체가 속성을 가지게 된다.
- 현실 : 수많은 개체가 존재 -> 공통점 발견 -> 이를 분류하기 위해 클래스(카테고리) 생성
- 가상 : 속성을 내포한 클래스 생성 -> 클래스를 통한 개체 생성 -> 공통점을 가짐
또한 인스턴스는 하나의 클래스만을 통해서 만들어진다.
이 말은 인스턴스를 생성할 때 호출할 수 있는 클래스는 오직 하나뿐이라는 뜻이다.
인스턴스가 여러 클래스에 속할 수는 있으나, 이 클래스들은 인스턴스 입장에서 '직계존속'이다.
02. 자바스크립트의 클래스
자바스크립트는 프로토타입 기반의 언어로 클래스가 존재하지 않았지만, 프로토타입을 클래스에 빗대어 해석할 수 있는 부분이 없지 않다.
바로 프로토타입 체이닝이다. 이를 상속과 비슷한 개념으로 볼 수 있다.
생성자 함수 Array를 new 와 함께 호출하면 인스턴스가 생성되는데, Array를 일종의 클래스라하면, Array의 prototype 객체 내부 요소들이 인스턴스에 '상속'되는 것이다.
인스턴스에 상속되는지 여부에 따라 '스태틱 멤버'와 '인스턴스 멤버'로 구분된다.
한편, 자바스크립트는 인스턴스에도 직접 메서드를 정의할 수 있어서 혼란을 방지하기 위해 '인스턴스 메소드'를 '프로토타입 메서드'라 부른다.
그림 7-4
var Rectangle = function(width, height) {
this.width = width;
this.height = height;
};
Rectangle.prototype.getArea = function() {
return this.width * this.height;
};
Rectangle.isRectangle = function(instance) {
return instance instanceof REctangle &&
instance.width > 0 && instance.height > 0;
};
var rect1 = new Rectangle(3,4)
console.log(rect1.getArea()); // 12 (0)
console.log(rect1.isRectangle(rect1); //Error
console.log(Rectangle.isRectangle(rect1); // true
Rectangle 함수를 new 와 함께 호출해 인스턴스를 만들고 rect1에 할당했다.
console.log를 통해 메서드를 사용한 값을 확인하면,
- getArea()는 프로토타입에 정의되어 rect1이 자기자신의 것처럼 직접 호출이 가능하다.
- isRectangle은 프로토타입에 정의되어있지 않아, rect1이 직접 호출이 불가능하다.
- isRectangle은 생성자 함수를 this로 해야만 호출이 가능하다. (rect1을 인자로 넘긴다)
그림 7-5
"프로그래밍 언어에서 클래스는 사용하기에 따라 추상적일 수도 있고, 구체적일 수도 있다."
정의한 '틀'의 역할을 담당하는 목적일 때의 클래스는 추상적이지만, 클래스 자체를 this로 해서 직접 접근해야하는 스태틱 메서드를 호출할때는 하나의 개체로서 취급된다.
6
03. 클래스 상속
3-1 기본 구현
프로토타입체인을 활용해서 클래스 상속을 구현한다.
ES5까지의 자바스크립트에는 클래스가 없었기 때문에, 클래스 상속을 구현했다는 건 곧 프로토타입 체이닝을 잘 연결한 것이다.
var Grade = function () {
var args = Array.prototype.slice.call(arguments);
for (var i=0; i <args.length; i++) {
this[i] = args[i];
}
}
Grade.prototype = [];
var g = new Grade(100,80);
위 코드에는 문제점이 있는데, 아래와 같다.
1. length 프로퍼티가 confiurable (삭제) 가능
2. Grade.prototype에 빈 배열을 참조
04. ES6의 클래스 및 클래스 상속
'프로그래밍 > javascript&typescript' 카테고리의 다른 글
Typescript (0) | 2021.09.09 |
---|---|
프론트엔트 개발환경이 복잡해진 이유 (0) | 2021.09.08 |
INTRO (0) | 2021.09.06 |
데이터 타입 (0) | 2020.03.26 |
06. 프로토타입 (0) | 2020.03.04 |