[JS] 자바스크립트도 클래스가 있나요?

고정원·2021년 7월 13일
0

1Q/1Day

목록 보기
13/13
post-thumbnail
post-custom-banner

정재남,『코어자바스크립트』를 읽고 정리한 내용입니다. 이해가 부족한 부분은 책과 동일하게 작성하였습니다.

자바스크립트는 프로토타입 기반 언어 → "상속"이라는 개념 없음
클래스기반의 타언어 개발자들에게 혼란을 주었고, 클래스와 비슷한 여러 기법들이 있긴했다. 결국 ES6에 클래스 문법이 추가되었지만, 일정부분 프로토타입을 활용하고 있기 때문에 ES5 체제 하에서 클래스를 흉내내기 위한 구현방식을 알고 있어야 한다.

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

클래스: 공통 요소를 지니는 집단을 분류하기 위한 개념 (추상적 혹은 구체적)**

  • 음식, 과일 같은 "범주"
    : 어떤 사물들의 공통 속성을 모아 정의한 것일 뿐 직접 만질 수도 볼 수도 없는 추상적인 개념

인스턴스: 어떤 클래스의 속성을 지니는 실존하는 개체 (구체적)

  • 범주 아래의 배,사과,바나나 등
    : 직접 만질 수 있고 볼 수도 있고 먹을 수 있는 구체적이고 실존하는 사물

음식은 과일보다 상위의 개념(상위클래스)이고, 과일은 음식보다 하위의 개념(하위클래스)이다.

💡과일 분류 하위에 또 다른 분류가 있으면, 클래스 간의 관계는 어떻게 될까?

클래스 간의 상하관계

  • 하위개념은 상위 개념을 포함하면서 더 구체적인 개념이 추가된다.
    → 클래스는 하위로 갈수록 상위 클래스의 속성을 상속하면서 더 구체화되지만, 결국 추상적인 개념이다.

현실과 프로그래밍에서의 클래스&인스턴스 접근 방식

현실세계

  • 클래스는 공통요소를 지니는 집단을 분류하기 위한 개념, 추상적인 개념
  • 인스턴스들로 부터 공통점을 발견해서 클래스를 정의

프로그래밍 언어

  • 클래스는 공통요소를 지니는 집단을 분류하기 위한 개념, 사용하기에 따라 추상적인 대상일 수도 있고 구체적인 개체가 될 수도 있다.
  • 클래스가 먼저 정의돼야만 그로부터 공통적인 요소를 지니는 개체 생성이 가능

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

예제 1 ) static method, prototype method

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

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

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

var rect1 = new Rectangle(3,4)
console.log(rect1.getArea()); //12(o)
console.log(rect1.isRectangle(rect1)); //Error(x)
console.log(Rectangle.isRectangle(rect1)); //true

🔹프로토타입 메서드
프로토타입 객체에 할당한 메서드는 인스턴스가 마치 자신의 것처럼 호출할 수 있다. 따라서 rect1.getArea()Rectangle.prototype.getArea을 실행시킨다. 이처럼 인스턴스에서 직접 호출할 수 있는 메서드가 프로토타입 메서드이다.

🔹스태틱 메서드
이와 다르게 rect1.isRectangle(rect1)은 접근이 불가능하여 에러를 발생시킨다. 이처럼 인스턴스에서 직접 접근할 수 없는 메서드가 스태틱 메서드이다. 스태틱 메서드는 Rectangle.isRectangle(rect1)처럼 생성자 함수를 this로 지정해야만 호출할 수 있다.

"프로그래밍 언어에서의 클래스는 사용하기에 따라 추상적일 수도 있고 구체적인 개체가 될 수 도 있다"
🙄뭔 말이여...?🙄
일반적인 사용 방식, 즉 구체적인 인스턴스가 사용할 메서드를 정의한 '틀'의 역할을 담당하는 목적을 가질 때의 클래스는 추상적인 개념이지만, 클래스 자체를 this로 해서 직접 접근해야만 하는 스태틱 메서드를 호출할 때의 클래스는 그 자체가 하나의 개체로서 취급된다.

3. 클래스 상속

3.1 기본 구현

상속은 객체지향의 꽃!
ES5까지 JS커뮤니티에서 클래스 상속을 다른 객체지향언어에 익순한 개발자들에게 친숙한 형태로 흉내 내는 것이 주요한 관심사였다. 이번 챕터에서는 프로토타입체인을 활용해 클래스 상속을 구현하고 최대한 전통적인 객체지향 언어에서의 클래스와 비슷한 형태로까지 발전시켜보는 것이 목표이다. 플러스, 이런 다양한 방식으로 고군분투해왔구나 정도로 읽어보자! 후에 ES6의 클래스 문법도 공부할거니까!

🤩프로토타입에서 다룬 프로토타입체인이 상속의 핵심이다
자바스크립트에서 클래스 상속을 구현했다는 것은 결국 프로토타입 체이닝을 잘 연결한 것!!

예제 2 )

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=[]; //g.__proto__ 가 빈 배열을 가리키고 있다.
var g = new Grade(100, 80);

두가지 문제점이 있다
1)length 프로퍼티가 삭제가능(configurable)하다
2) Grade.prototype에 "빈 배열"을 참조 시켰다

...
g.push(90); 
console.log(g); //Grade { 0:100, 1:80, 2:90, length:3}

delete g.length;
g.push(70);
console.log(g); //Grade { 0:70, 1:80, 2:90, length:1}

💡내장객체인 배열 인스턴스의 length프로퍼티는 configurable 속성이 false라서 삭제가 불가능
하지만!! Grade 클래스의 인스턴스는 배열 메서드를 상속하지만 기본적으로는 일반 객체의 성질을 그대로 지니므로 삭제가 가능해서 문제이다!

잠깐... push했을 때, 어떻게 0번째 인덱스에 70이 들어가고 length가 다시 1이 되었을까?
g.__proto__,즉 Grade.prototype이 빈 배열을 가리키고 있기 때문에 가능했다.

push 명령에 따라 JS엔진은 g.length를 읽으려는데 없으니까 프로토타입 체이닝을 타고 g.__proto__.length를 읽어온 것이다. 빈 배열의 length는 0이므로 여기에 값을 할당하고, length는 1만큼 증가시키라는 명령이 문제 없이 작동했다.

그럼 만약 Grade.prototype에 "요소를 포함하는 배열을 매칭"시켰다면?

Grade.prototype = ['a','b','c','d'];
var g = new Grade(100, 80);

g.push(90); 
console.log(g); //Grade { 0:100, 1:80, 2:90, length:3}

delete g.length;
g.push(70);
console.log(g); //Grade { 0:100, 1:80, 2:90, ___4:70, length: 5}

length삭제 전까지는 동일하나, length를 삭제하고 나니 빈배열을 매칭했을때와 다르게 동작했다.
g.length가 없으니까 g.__proto__.length를 찾고, 값이 4이므로 인덱스 4에 70을 넣고, 다시 g.length에 5를 부여하는 순서로 동작한 것이다.

이렇게 클래스에 있는 값이 인스턴스의 동작에 영향을 주어서는 안될텐데...🤔
인스턴스와의 관계에서는 구체적인 데이터를 지니지 않고 오직 인스턴스가 사용할 메서드만을 지니는 추상적인 "틀"로서만 작용하도록 작성해야 위의 예제같은 예기치 않은 오류를 없앨 수 있다.

(ES5까지의 클래스 상속구현은 문제가 발생할 여지가 있었다. 그래서 ES6에서 클래스 문법이 도입되었다.)

근데... 클래스의 추상성을 지키는게 왜 중요할까?!
상위 클래스의 데이터가 오염되면, 상위클래스의 공통성질을 참조하고 있는 다른 수많은 하위클래스까지 데이터 오염이 일어나기 때문이다.

추상성

  • 본질적, 보편적, 관념적 성질. 즉, 공통성질.

추상화

  • 개별의 사물이나 표상의 공통된 속성이나 관계 따위를 뽑아내는 것.
  • 복잡한 자료, 모듈, 시스템 등으로부터 핵심적인 개념 또는 기능을 간추려 내는 것.
  • 공통부분을 상위 클래스/인터페이스로 모으는 일.
  • 모듈의 기능을 쉽게 이용할 수 있도록 단순화하는 일.

정리

  • 자바스크립트는 프로토타입 기반 언어라서 클래스 및 상속 개념은 존재하지 않지만 프로토타입을 기반으로 클래스와 비슷하게 동작하게끔 하는 다양한 기법들이 도입되어 왔다.
  • 클래스는 어떤 사물의 공통속성을 모아 정의한 추상적인 개념이고, 인스턴스는 클래스의 속성을 지니는 구체적인 사례이다. 상위 클래스(superclass)의 조건을 충족하면서 더욱 구체적인 조건이 추가된 것을 하위 클래스(subclass)라고 한다.
  • 클래스의 prototype 내부에 정의된 메서드를 프로토타입 메서드라고 하며, 이들은 인스턴스가 마치 자신의 것처럼 호출할 수 있다. 한편 클래스(생성자함수)에 직접 정의한 메서드를 스태틱 메서드라고 하며, 이들은 인스턴스가 직접 호출할 수 없고 클래스(생성자함수)에 의해서만 호출할 수 있다.

[참고한자료]
정재남, 『코어자바스크립트』, 위키북스(2019)
JavsScript - Classes | MDN
https://velog.io/@jeanbaek/07-클래스

profile
해결문제에 대해 즐겁게 대화 할 수 있는 프론트엔드 개발자
post-custom-banner

0개의 댓글