-
[Group Study, 모던 자바스크립트 Deep Dive] - 25 클래스 Part1Front-end/Javascript 2022. 12. 11. 15:31반응형
Group study background
나만 그런건지는 모르겠지만, 실무를 하다보면 잊어버리는 개념들이 있다.
가끔 FE 뉴비나 novice인분들에게 질문을 받는데, 아리송 할때만큼 쪽팔릴때가 없었다.
인간은 망각의 동물이라고 교수님께서 말씀하셨지만 반복 학습의 힘을 믿는다. React 오픈카톡방에서 모집한 스터디원분들과 함께 "모던 자바스크립트 Deep Dive" 1권 톺아보기를 시작한다!
정보 전달용이 아닌 개인 스터디 레코딩용 포스트입니다.
25.1 클래스는 프로토타입의 문법적 설탕인가?
자바스크립트는 프로토타입 객체지향 언어이다. (kidding)JS는 근본 논란으로 여러 놀림도 있고 다른 언어와의 차이로 인해 여러 논쟁이 있긴하지만 무튼 객체지향 언어이다.
프로토타입 기반 객체지향 언어는 클래스가 필요 없는 객체지향 프로그래밍 언어다. 하지만 ES5에서는 클래스 없이도 아래 예제처럼 생성자 함수와 프로토타입을 통해 객체지향 언어의 상속을 구현할 수 있다.
[예제 25-01]
var Person = (function() { function Person(name) { this.name = name } Person.prototype.sayHi = function() { console.log(this.name + ', Hi') } return Person }) var me = new Person('Daniel'); me.sayHi()
위의 예제느 JS를 첫 언어로 시작하지 않은 사람에게는 꽤나 생소하고 새로 배워야할 개념이 될것 같다. 이후 ES6에서 클래스가 도입되어 유사한 객체지향 프로그래밍을 할수 있도록 되었다.
클래스는 함수이고 기존 프로토타입 기반 패턴을 클래스 기반 패턴처럼 사용할 수 있도록 하는 문법적 설탕(Syntax Sugar)이라 할 수 있지만 아래에서 볼 수 있듯이 모든 기능이 100% 매칭이 되지는 않는다.
- 클래스를 new 연산자 없이 호출하면 에러가 발생한다. 하지만 생성자 함수를 new 연산자 없이 호출하면 일반 함수로 호출된다.
- 클래스는 상속을 지원하는 extends와 super 키워드를 제공한다. 하지만 생성자 함수는 그렇지 않다.
- 클래스는 호이스팅이 발생하지 않는 것처럼 동작한다. 하지만 함수 선언문으로 정의된 생성자 ㅎ마수는 함수 호이스팅이, 함수 표현식으로 정의한 생성자 함수는 변수 호이스팅이 발생한다.
- 클래스 내의 모든 코드에는 암묵적으로 strict mode를 해제할 수 없다.
- 클래스의 constructor, 프로로타입 메서드, 정적 메서드는 모드 프로퍼티 어트리뷰트 [[Enumerable]] 값이 false다.
25.2 클래스 정의
아래 예제처럼 클래스는 크게 3가지 방법으로 선언할 수 있다.
클래스를 표현식으로 정의할 수 있다는 것은 클래스가 값으로 사용할 수 있는 일급 객체라는 것을 의미한다.
- 무명의 리터럴로 생성할 수 있다. (즉. 런타임)
- 변수나 자료구조(객체, 배열 등)에 저장할 수 있다.
- 함수의 매개변수에 전달할 수 있다.
- 함수의 반환값으로 사용할 수 있다.
[예제 25-02]
// 클래스 선언문 class Person {} // 익명 클래스 표현식 const Person = class {} // 기명 클래스 표현식 const Person = class MyClass{}
[예제 25-03]
// 클래스 선언문 class Person { //생성자 constructor(name){ //인스턴스 생성 및 초기화 } //프로토타입 메서드 sayHi() { console.log(this.name, 'Hi') } static sayHello() { console.log('hello') } } //인스턴스 생성 const me = new Person("Daniel") // 인스턴스 프로퍼티 참조 console.log(me.name) //프로토타입 메서드 호출 me.sayHi() //정적 메서드 호출 Person.sayHello();
[그림 25-01]
25.3 클래스 호이스팅
클래스는 함수로 평가된다.
클래스 선언문으로 정의한 클래스는 함수 선언문과 같이 소스코드 평가 과정, 즉 런타임 이전에 먼저 평가되어 함수 객체를 생성한다. 이때 클래스가 평가되어 생성된 함수 객체는 생성자 함수로서 호출할 수 있는 함수, 즉 constructor다.
클래스 선언문도 변수, 함수 선언과 마찬가지로 호이스팅이 발생한다. 단, let, const 키워드로 선언한 변수처럼 호이스팅 된다. 따라서 TDZ(Temporal Dead Zone)에 빠지기 때문에 호이스팅이 발생하지 않는 것처럼 동작한다.
25.4 인스턴스 생성
클래스는 생성자 함수이며 new 연산자와 함께 호출되어 인스턴스를 생성한다.
클래스 표현식으로 정의된 클래스의 경우 클래스를 가리키는 식별자(Person)를 사용해 인스턴스를 생성하지 않고 기명 클래스 표현식의 클래스 이름(MyClass)을 사용해 인스턴스를 생성하면 에러가 발생한다. (예제 25-02 참고)
25.5 메서드
25.5.1 constructor
constructor는 인스턴스를 생성하고 초기화하기 위한 특수한 메서드다.
모든 함수 객체가 가지고 있는 prototype 프로퍼티가 가리키는 프로토타입 객체의 constructor 프로퍼티는 클래스 자신을 가리키고 있다. 이는 클래스가 인스턴스를 생성하는 생성자 함수라는 것을 의미한다. 즉 new 연산자와 함께 클래스를 호출하면 클래스는 인스턴스를 생성한다.
- 인스턴스를 생성할 때 클래스 외부에서 인스턴스 프로퍼티의 초기값을 전달하려면 매개변수를 선언하고 인스턴스를 생성할 때 초기값을 전달한다.
- constructor는 별도의 반환문을 갖지 않는다. 암묵적으로 this를 반환한다
[그림 25-02]
constructor는 메서드로 해석되는 것이 아니라 클래스가 평가되어 생성한 함수 객체 코드의 일부가 된다.
constructor를 생략하면 클래스에 다음과 같이 빈 constructor가 암묵적으로 정의된다.
[그림 25-03]
25.5.2 프로토타입 메서드
생성자 함수를 사용하여 인스턴스를 생성하는 경우 프로토타입 메서드를 성성하기 위해서 명시적으로 프로토타입에 메서드를 추가해야 한다. 하지만, 클래스 코드 내에 정의한 메서드는 생성자 함수에 의한 객체 생성 방식과는 다르게 클래스의 prototype 프로퍼티에 메서드를 추가하지 않아도 기본적으로 프로토타입 메서드가 된다.
프로토타입 체인은 기존의 모든 객체 생성 방식뿐만 아니라 클래스에 의해 생성된 인스턴스에도 동일하게 적용된다. 생성자 함수의 역할을 클래스가 할 뿐이다.
[예제 25-04]
// 클래스 선언문 class Person { //생성자 constructor(name){ //인스턴스 생성 및 초기화 } //프로토타입 메서드 sayHi() { console.log(this.name, 'Hi') } } const me = new Person('Daniel') //me객체의 프로토타입은 Person.prototype Object.getPrototypeOf(me) === Person.prototype // true me instanceof Person Object.getPrototypeOf(Person.prototype) === Object.prototype // true me instanceof Object me.constructor === Person //true
[그림 25-04]
25.5.3 정적 메서드
정적 메서드는 인스턴스를 생성하지 않아도 호출할 수 있는 메서드이다.
정적 메서드는 인스턴스로 호출할 수 없다. 정적 메서드가 바인딩된 클래스는 인스턴스의 프로토타입 체인상에 존재하지 않기 때문이다. 즉, 인스턴스의 프로토타입 체인 상에는 클래스가 존재하지 않기 때문에 인스턴스로 클래스의 메서드를 상속받을 수 없다.
[그림 25-05]
25.5.4 정적 메서드와 프로토타입 메서드 차이
- 정적 메서드와 프로토타입 메서드는 자신이 속해 있는 프로토타입 체인이 다르다
- 정적 메서드는 클래스로 호출, 프로토타입 메서드는 인스턴스로 호출
- 정적 메서드는 인스턴스 프로퍼티를 참조할 수 없지만, 프로토타입 메서드는 인스턴스 프로퍼티를 참조할 수 있다.
25.5.5 클래스에서 정의한 메서드의 특징
- function 키워드를 생략한 메서드 축약 표현 사용
- 객체 리터럴과는 다르게 클래스에 메서드를 정의할 때 콤마 불필요
- 암묵적으로 strict mode
- for ... in, Object.keys 메서드로 열거할 수 없다.
- 내부 메서드 [[Constructor]]를 갖지 않는 non-construtor이다. 따라서 new 연산자와 함께 호출할 수 없다.
25.6 클래스의 인스턴스 생성 과정
1. 인스턴스 생성과 this 바인딩
new 연산자와 함께 클래스를 호출하면 constructor의 내부 코드가 실행되기에 앞서 암묵적으로 빈 객체가 생성된다. 이 빈 객체가 바로 클래스가 생성한 인스턴이다. 이때 클래스가 생성한 인스턴스의 프로토타입으로 클래스의 prototype프로퍼티가 가리키는 객체가 설정된다. 그리고 암묵적으로 생성된 빈 객체, 즉 인스턴스는 this에 바인딩 된다. 따라서 constructor 내부의 this는 클래스가 생성한 인스턴스를 가리킨다.
2. 인스턴스 초기화
constructor의 내부 코드가 실행되어 this에 바인딩되어 있는 인스턴스를 초기화한다. 즉, this에 바인딩되어 있는 인스턴스에 프로퍼티를 추가하고 cosntructor가 인수로 전달받은 초기값으로 인스턴스의 프로퍼티 값을 초기화한다.
3. 인스턴스 반환
클래스의 모든 처리가 끝나면 완성된 인스턴스가 바인딩된 this가 암묵적으로 반환된다.
반응형'Front-end > Javascript' 카테고리의 다른 글
[Group Study, 모던 자바스크립트 Deep Dive] - 27 배열 (0) 2022.12.15 [Group Study, 모던 자바스크립트 Deep Dive] - 25 클래스 Part2 (0) 2022.12.11 [Group Study, 모던 자바스크립트 Deep Dive] - 24 클로저 Part2 (0) 2022.11.27 [Group Study, 모던 자바스크립트 Deep Dive] - 24 클로저 Part1 (0) 2022.11.20 [Group Study, 모던 자바스크립트 Deep Dive] - 23 실행 컨텍스트 Part 1 (0) 2022.11.15