한준호

[Modern javascript] 클래스(1) 본문

Frontend/modern javascript

[Modern javascript] 클래스(1)

igoman2 2021. 8. 31. 21:53
728x90

프로토타입 기반 객체지향 언어는 클래스가 필요없는 객체지향 언어이므로 자바스크립트의 클래스는 문법적 설탕이라고 보이기도 한다.

 

■ 클래스 정의

일반적으로 클래스는

// 클래스 선언문
class Person {}

와 같이 선언한다.

// 익명 클래스 표현식
const Person = class {};

// 기명 클래스 표현식
const Person = class MyClass {};

- 클래스도 함수이다.

- 클래스는 이름을 갖지 않을 수도 있다.

- 클래스는 표현식으로 정의할 수 있다.

- 표현식으로 정의 가능하므로 일급 객체이다.

  •  무명의 리터럴로 생성. 즉, 런타임에 생성이 가능하다.
  •  변수나 자료구조에 저장할 수 있다.
  •  함수의 매개변수에 전달할 수 있다.
  •  함수의 반환값으로 사용할 수 있다.

 

 

■ 클래스 호이스팅

클래스도 호이스팅은 되지만 일시적 사각지대가 존재한다.

(var, let, const, function, functions*, class 키워드는 모두 호이스팅이 된다.)

 

 

■ 인스턴스 생성

클래스는 new 연산자와 함께 호출한다.

 

 

■ 메서드

- 생성자, 프로토타입 메서드, 정적 메서드가 있다.

- 클래스도 함수 고유의 프로퍼티를 가지고 있다. 함수와 동일하게 프로토타입과 연결되어 있으며 자신만의 스코프 체인을 구성한다.

- constructor 내부의 this는 클래스가 생성한 인스턴스를 가리킨다.

 

constructor는 다음과 같은 특징을 가진다.

1. constructor는 클래스 내에 최대 한 개만 존재할 수 있다.

2. constructor는 생략할 수 있다. (암묵적으로 빈 객체 생성)

3. constructor 내부에서 return문은 클래스 기본 동작을 훼손하므로 생략한다.

 

- 클래스 몸체의 메서드는 생성자 함수에 의한 객체 생성 방식과 다르게 prototype 프로퍼티에 메서드를 추가하지 않아도 기본적으로 prototype 메서드가 된다.

- 클래스가 생성한 인스턴스는 프로토타입 체인의 일원이 된다.

- 생성자 함수의 경우 정적 메서드를 다음과 같이 명시적으로 추가해야했지만

// 생성자 함수
function Person(name) {
  this.name = name;
}

// 정적 메서드
Person.sayHi = function () {
  console.log('Hi!');
};

// 정적 메서드 호출
Person.sayHi(); // Hi!

클래스에서는 메서드에 static 키워드를 붙이면 된다.

class Person {
  // 생성자
  constructor(name) {
    // 인스턴스 생성 및 초기화
    this.name = name;
  }

  // 정적 메서드
  static sayHi() {
    console.log('Hi!');
  }
}

- 정적 메서드는 인스턴스로 호출할 수 없다.

// 정적 메서드는 클래스로 호출한다.
// 정적 메서드는 인스턴스 없이도 호출할 수 있다.
Person.sayHi(); // Hi!


// 인스턴스 생성
const me = new Person('Lee');
me.sayHi(); // TypeError: me.sayHi is not a function

 

◎ 정적 메서드와 프로토타입 메서드의 차이

1. 속해있는 프로토타입 체인이 다르다.

2. 정적 메서드는 클래스로 호출하고 프로로타입 메서드는 인스턴스로 호출한다.

3. 정적 메서드는 인스턴스 프로퍼티를 참조할 수 없지만 프로토타입 메서드는 인스턴스 프로퍼티를 참조할 수 있다.

 

아래 예제를 보자

class Square {
  // 정적 메서드
  static area(width, height) {
    return width * height;
  }
}

console.log(Square.area(10, 10)); // 100
class Square {
  constructor(width, height) {
    this.width = width;
    this.height = height;
  }

  // 프로토타입 메서드
  area() {
    return this.width * this.height;
  }
}

const square = new Square(10, 10);
console.log(square.area()); // 100

프로토타입 메서드는 인스턴스로 호출, this는 생성할 인스턴스를 가리키게 된다.

정적 메서드는 클래스로 호출, this는 클래스를 가리키게 된다. 

즉 this의 사용 여부에 따라 메서드를 구분하는 것이 좋다. (this를 사용하지 않더라도 프로토타입 메서드로 정의할 수 있다.)

 

다만 다음과 같이 함수를 하나의 클래스 또는 생성자 함수를 하나의 네임스페이스로 사용하여 정적 메서드를 모아 놓으면 관련 함수를 구조화 하는데 좋다.

// 표준 빌트인 객체의 정적 메서드
Math.max(1, 2, 3);          // -> 3
Number.isNaN(NaN);          // -> true
JSON.stringify({ a: 1 });   // -> "{"a":1}"
Object.is({}, {});          // -> false
Reflect.has({ a: 1 }, 'a'); // -> true

 

◎ 클래스에서 정의한 메서드의 특징

1. function 키워드를 생략

2. 콤마가 필요 없다.

3. 암묵적으로 strict mode이다.

4. 열거할 수 없다. (프로퍼티 어트리뷰트 [[Enurable]]의 값이 false이다.)

5. 내부 메서드 [[Construct]]를 갖지 않는 non-constructor다.

 

 

■ 클래스 인스턴스 생성 과정

1. 인스턴스 생성과 this 바인딩

new로 constructor호출하면 암묵적으로 빈 객체가 생성되며 클래스가 생성한 인스턴스의 프로토타입으로 클래스의 prototype 프로퍼티가 가리키는 객체가 설정되고 this가 바인딩된다.

 

2. 인스턴스 초기화

constructor 내부 코드가 실행되면서 this에 바인딩된 인스턴스를 초기화한다.

 

3. 인스턴스 반환

바인딩된 this 반환

 

728x90
Comments