클래스(class) 심화

minho·2021년 12월 5일
0

클래스와 인스턴스


먼저 인스턴스를 설명하자면, 그림에서 보듯이 배나 사과등은 어떤 공통된 속성을 지닌다. 그래서 과일이라는 항목에 묶여 있는 것이다.
즉, 공통된 속성을 지닌 구체적인 대상들을 인스턴스라고 한다.

반대로 이 인스턴스들의 공통 속성을 모은 추상적인 개념이 곧 '클래스'이다.

슈퍼클래스(superclass)와 서브클래스(subclass)


그림처럼 과일 클래스를 지정하려면 과일보다 더 추상적인 음식클래스를 상위클래스(supercalss)로 지정해야한다. 그리고 과일클래스를 음식클래스 안에 넣어주면 과일 클래스는 음식클래스의 하위클래스(subclass)로 된다.

단일 클래스


위에서 클래스는 객체의 속성을 정의한다.
이렇게 정의된 객체를 인스턴스라고 한다.


Array.prototype의 메소드로 정의되지 않고 Array에 직접할당되는 함수는 static methods라 하며, 직접할당되는 프로퍼티는 static properties라고 한다.
이들은 new연산자 없이 함수(객체)로써 호출할 때만 의미가 있는 값들이다.


한편 prototype에 정의되어 있는 함수들을 (prototype)methods라고 한다.

인스턴스에서의 접근


인스턴스에서 prototype methods로는 [[Prototype]]을 통해 접근이 가능하다.

그러나 생성자 내부에 정의되어있는 함수나 프로퍼티에는 직접 접근할 방법이 없다.
Ex)

prototype의 메소드로 정의된 getName()과 getAhe()는 인스턴스인 roy의 프로토타입 체이닝으로 사용이 가능하지만, 클래스인 Person의 직접적으로 정의된 함수 getInformations()는 roy로 직접접근이 불가능 하기 때문에 ERROR가 발생한다.

그러므로 위의 사진처럼 Person에서 직접 접근하도록 한다.

클래스 상속


Person이 상위클래스 이고 그 밑에 Emplyee가 하위클래스인 경우이다.
이 클래스에서 연두색 박스부분인 getName()과 getAge()부분이 겹친다.
이러한 경우에는 어떻게 해야 할까?


위와같이 Employee는 Person의 getName()과 getAge()를 상속받고 getPosition()은 Employee의 prototype의 메소드로 정의하면 간단하게 해결된다.

그렇다면 이걸 코드로 어떻게 표현할까?

먼저 Employee의 오른쪽과 Person의 밑에 꼭지점을 연결해야 한다.
Employee의 오른쪽에 해당하는 곳은 Employee.prototye에 해당하는 곳으로, Employee.prototye를 Person의 인스턴스로 만들면 된다.
그래서 이렇게 연결이 된다.

그러나 Employee.prototye는 원래 Employee의 프로퍼티 였지만 Person의 인스턴스로 완전히 새롭게 정의되었다.

그래서 여타의 프로토타입과 동일하게 동작해주기 위해서는 본래 가지고 있던 기능을 다시 부여해 줄 필요가 있다.

Employee.prototye의 본래역할은 Employee의 프로퍼티 역할이므로 이를 정의하기 위해 constructor를 사용한다.
constructor는 생성자라는 뜻으로 Employee.prototye의 생성자는 Employee라는 것을 정의해 줌으로써 Employee의 프로퍼티 역할을 다시 부여해준다.

이렇게 하면 다른 두개의 클래스가 슈퍼클래스 서브클래스 관계를 갖게 된다.

이를 코드로 정리하면, 먼저 Employee.prototype과 Person을 연결해주고, Employee.prototype의 본래기능을 재정의 해준다.

그 후에 Employee의 메소드인 getPosition()을 만들어 준다.
그런데 이 부분은 굳이 왜 제일 밑에다 넣었을까?
이유는 getPosition()을 먼저 정의하면, 연결과정에서 Employee.prototype을 다시 재정의 하기 때문에 먼저 정의한 getPosition()은 사라진다.

Employee를 출력하면 이렇게 나온다. 문제는 사진에 표시된 부분이다.

만약에 Employee의 name부분을 지워버린 후 name을 출력한다면 프로토타입 체이닝으로 Person의 name이 출력된다.

즉, 이 그림에서 빨간색 부분을 지워줘야 한다.
저 빨간부분은 Person의 프로퍼티에 해당한다.
사실 Employee가 필요한건 Person의 prototype만 필요하다.
그러므로 빈 객체를 만들어주어 아무런 프로퍼티도 존재하지 않게 하면 되지 않을까?

위와같이 Bridge라는 빈 객체를 만든다
이 Bridge의 prototype에 Person의 prototype을 연결한 상태에서 인스턴스를 생성하면 그 인스턴스는 아무런 프로퍼티 없이 메소드만 상속받는다.

이런식으로 Person의 prototype과 Bridge의 prototype을 연결하고 Bridge의 인스턴스로 Emplyee.prototype을 만들면 된다.

그 결과 이런그림이 된다.

이를 코드로 표현하면 이렇다.
1. 빈 객체인 Bridge()를 만들어 준다.
2. Bridge()의 prototype과 Person()의 prototype을 연결해준다.
3. Employee의 prototype을 Bridge()의 인스턴스로 만든다.
4. Employee의 prototype의 기능을 재정의 하기 위해 constructor를 Employee로 정해준다.
정리를 하자면 Bridge()를 이용해서 Person의 인스턴스 관계를 끊음으로써 불필요한 프로퍼티가 프로토타입 체인으로 상속되지 않게 한다.


ES5에서는 Bridge()는 실제 코드상에 영향을 주는 녀석이 전혀 아니기 때문에 이런식으로 함수화 시켜서 활용할 것을 추천하고 있다.

그래서 이렇게 보다 간단한 형태로 상속을 구현할 수 있다.

인스턴트 value의 관점에서 상속구조를 활용



Person의 인스턴스와 Employee의 인스턴스 모두 name, age라는 똑같은 프로퍼티를 가지므로 extendClass에 superlcass라는 메소드를 상위클래스인 Parent로 지정하면 간단하게 사용이 가능하다.

여기서 Employee의 인스턴스인 roy는 superClass라는 메소드가 없으니까 프로토타입 체이닝을 타고 Employee.prototype 내부에서 superClass를 검색하고 있으니 해당 메서드를 실행한다.

superClass 메서드에는 Parent, 즉 Person이 연결 되어 있다. 그리고 superClass를 메소드로 호출했으므로 this는 roy를 가리키게 된다.

그러므로 최종본을 보자면 이렇게 된다.

ES6에서 구현

ES6에서는 굳이 extendClass라는 함수를 직접 만들어서 구현하지 않아도 자바스크립트 내장 명령으로 손쉽게 클래스 상속을 구현할 수 있다.
이와 같이 Employee가 Person을 extends해주기만 하면 클래스 상속이 된다.
constructor()로 프로퍼티를 정의해주고, super()로 상속받을 수 있다.

profile
Live the way you think

0개의 댓글