📌 클래스란?
자바스크립트에서 클래스는 함수의 한 종류입니다. 따라서 값으로 사용할 수 있는 일급 객체입니다.
일급 객체의 특징
- 무명의 리터럴로 생성 가능 (런타임에 생성 가능)
- 변수나 자료구조에 저장 가능
- 함수의 매개변수에게 전달 가능
- 함수의 반환값으로 사용 가능
기본 문법
class Person {
constructor(name, age) { // 생성자
// 인스턴스 생성 및 초기화
this.name = name;
this.age = age;
}
introduce() { // 프로토타입 메서드
console.log(`Hello, My name is ${this.name}`);
}
static sayHi() { // 정적
console.log('hi');
}
}
const jack = new Person("jack", 17); // 인스턴스 생성
jack.introduce(); // Hello, My name is jack
Person.sayHi(); // hi
클래스 호이스팅
클래스는 함수로 평가됩니다.
class Person {}
console.log(Person); // function
클래스 선언문으로 정의한 클래스는 함수 선언문과 같이 런타임 이전에 먼저 평가되어 함수 객체를 생성합니다.
const Person = '';
{
console.log(Person);
// ReferenceError: Cannot access 'Person' before initialization
class Person {}
}
위 코드에서 클래스가 호이스팅 되지 않는다면 ‘’
이 나와야 하지만 참조 에러가 나옵니다. 이것으로 변수 선언문, 함수 선언문과 마찬가지로 클래스 선언문도 호이스팅이 발생한다는 것을 알 수 있습니다.
📌 인스턴스 생성
new 연산자를 사용하여 인스턴스를 생성합니다.
class Person {}
const person = new Person();
console.log(person); // Person {}
new
를 사용하냐 안 하냐에 따라서 일반 함수 호출이냐 인스턴스 생성을 위한 생성자 함수 호출이냐가 달라지므로 반드시 new
를 사용해야 합니다.
📌 메서드
constructor
constructor는 인스턴스를 생성하고 초기화하기 위한 특수한 메서드입니다.
class Person {
constructor(name) {
this.name = name;
}
}
constructor 주의점
- 이름 변경이 불가능합니다.
- 2개 이상의 constructor가 존재하면 에러가 발생합니다.
- 생략할 수 있습니다. ( 빈 constructor가 암묵적으로 정의됩니다.)
- 고정값으로 인스턴스를 초기화할 수 있습니다.
- constructor에서 전달된 인자를 받아 초기화할 수 있습니다.
- 별도의 반환문을 갖지 않아야 합니다.
- 다른 객체를 명시적으로 반환하면 this(인스턴스)가 반환되지 않고 객체가 반환됩니다.
클래스의 constructor 메서드와 프로토타입의 constructor 프로퍼티는 직접적인 관련이 없습니다.
프로토타입의 constructor 프로퍼티는 모든 프로토타입이 가지고 있으며, 생성자 함수를 가리킵니다.
프로토타입 메서드
클래스에서 정의한 메서드는 인스턴스의 프로토타입에 존재하는 프로토타입 메서드가 됩니다.
class Person {
constructor(name, age) { // 생성자
// 인스턴스 생성 및 초기화
this.name = name;
this.age = age;
}
introduce() { // 프로토타입 메서드
console.log(`Hello, My name is ${this.name}`);
}
}
const jack = new Person("jack", 17); // 인스턴스 생성
jack.introduce(); // Hello, My name is jack
Object.getPrototypeOf(jack) === Person.prototype; // true
jack instanceof Person; // true
Object.getPrototypeOf(Person.prototype) === Object.prototype; // true
jack instanceof Person; // true
jack.constructor === Person; // true
정적 메서드
정적 메서드는 인스턴스를 생성하지 않아도 호출할 수 있는 메서드입니다.
클래스에서는 메서드에 static을 붙이면 됩니다.
class Person {
constructor(name, age) { // 생성자
// 인스턴스 생성 및 초기화
this.name = name;
this.age = age;
}
static sayHi() { // 정적
console.log('hi');
}
}
Person.sayHi(); // hi
정적 메서드는 클래스에 바인딩된 메서드입니다.
클래스는 함수 객체로 평가되어서 자신의 프로퍼티와 메서드를 소유할 수 있습니다.
따라서 클래스 자체 소유인 정적 메서드는 프로토타입 메서드와 달리, 인스턴스를 생성하지 않고 호출할 수 있습니다.
하지만 인스턴스에서는 호출할 수 없습니다. 인스턴스의 프로토타입 체인 상에는 클래스가 없기 때문입니다.
const jack = new Person('jack');
jack.sayHi(); // Error
Person.sayHi(); // hi
정적 메서드와 프로토타입 메서드의 차이
- 정적 메서드와 프로토타입 메서드는 자신이 속해 있는 프로토타입 체인이 다릅니다.
- 정적 메서드는 클래스로 호출하고, 프로토타입 메서드는 인스턴스로 호출합니다.
- 정적 메서드는 인스턴스 프로퍼티를 참조할 수 없지만, 프로토타입 메서드는 인스턴스 프로퍼티를 참조할 수 있습니다.
📌 클래스의 인스턴스 생성 과정
class Person {
constructor(name) {
// 암묵적으로 인스턴스가 생성되고 this에 바인딩
console.log(this); // Person {}
console.log(Object.getPrototypeOf(this) === Person.prototype); // true
// this에 바인딩되어 있는 인스턴스를 초기화
this.name = name;
// 완성된 인스턴스가 바인딩된 this가 암묵적으로 반환
}
}
📌 프로퍼티
인스턴스 프로퍼티
인스턴스 프로퍼티는 constuctor 내부에서 정의해야합니다.
class Person {
constructor(name) {
// 인스턴스 프로퍼티
this.name = name; // name 프로퍼티는 public
}
}
const kim = new Person('kim');
console.log(kim.name); // kim
constructor 내부에서 this에 추가한 프로퍼티는 언제나 클래스가 생성한 프로퍼티가 됩니다.
원래는 자바스크립트에선 private 같은 접근 제한자를 지원하지 않아서 인스턴스 프로퍼티는 언제나 public 했지만, ES2022에서 #를 추가해서 private class field를 선언할 수 있게 되었습니다.
class Human {
static #is(type) {
return type === 'human';
}
#isHuman() {
return Human.#is('human');
}
isMan() {
return this.#isHuman();
}
}
new Human().isHuman // undefined
Human.is // undefined
new Human().isMan() // true
접근자 프로퍼티
접근자 프로퍼티는 자체적으로 값을 갖지 않고 다른 데이터 프로퍼티의 값을 읽거나 저장할 때 사용하는 접근자 함수로 구성된 프로퍼티입니다.
class Person {
constructor(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
get fullName() {
return `${this.firstName} ${this.lastName}`;
}
set fullName(name) {
[this.firstName, this.lastName] = name.split(' ');
}
}
const p = new Person('HeungMin', 'Son');
console.log(`${p.firstName} ${p.lastName}`); // HeungMin Son
p.fullName = 'InBeom Hwang'; // setter 함수 호출
console.log(p.fullName); // { firstName: 'InBeom', lastName: 'Hwang' }
// getter 함수 호출
console.log(p.fullName); // 'InBeom Hwang'
📌 super와 extends를 활용한 클래스 확장
extends
상속을 통해 클래스를 확장하려면 extends 키워드를 활용합니다.
주의할 점은 extends 키워드 앞에는 무조건 클래스가 와야 합니다.
super
super 키워드는 함수처럼 호출이 가능하고, this 처럼 식별자처럼 참조할 수 있는 키워드입니다.
- super를 호출하면 수퍼클래스의 constructor를 호출합니다.
- super를 참조하면 수퍼클래스의 메서드를 호출할 수 있습니다.
super 호출 시 주의사항
- 서브클래스에서 constructor를 생략하지 않는 경우 서브클래스의 constructor에서는 반드시 super를 호출해야합니다.
- 서브클래스의 constructor에서 super를 호출하기 전에는 this를 참조할 수 없습니다.
- super는 반드시 서브클래스의 constructor에서만 호출합니다. 서브클래스가 아닌 클래스의 constructor나 함수에서 super를 호출하면 에러가 발생합니다.
예제 코드로 알아봅시다.
class Human {
constructor(name, sex, age) {
this.name = name;
this.sex = sex;
this.age = age;
}
eat() {
console.log(`${this.name} eat`);
}
sleep() {
console.log(`${this.name} sleep`);
}
}
class Student extends Human {
constructor(name, sex, age, grade) {
super(name, sex, age);
this.grade = grade;
}
study() {
console.log(`${this.name} study`);
}
}
const kim = new Human("kim", "male", 21);
const jack = new Student("jack", "male", 18, 2);
console.log(kim.name); // kim
kim.eat(); // kim eat
console.log(jack.name); // jack
console.log(jack.grade); // 2
jack.eat(); // jack eat
jack.study(); // jack study
먼저 부모클래스가 될 Human 클래스를 정의합니다.
그 다음, extends 키워드를 활용해 Student 클래스에 Human 클래스를 상속시킵니다.
Student 클래스의 constructor 에서 부모클래스의 속성을 super를 호출하여 상속받습니다.
또한 eat 메서드와 sleep 메서드도 상속받았습니다.
따라서 Student의 인스턴스인 jack은 Human의 속성인 name, sex, age를 사용할 수 있고,
eat(), sleep() 메서드도 사용할 수 있습니다.
mdn과 모던 자바스크립트 딥다이브를 공부하며 정리한 글입니다.
'JavaScript' 카테고리의 다른 글
[JavaScript] 프로토타입 (prototype) (0) | 2023.03.15 |
---|---|
[JavaScript] 클로저 (Closure) (0) | 2023.03.15 |
[JavaScript] 원시 자료형과 참조 자료형 (0) | 2023.03.15 |
[JavaScript] if와 else if에서의 문제 해결 (0) | 2023.03.15 |
[JavaScript] 조건문과 반복문 (0) | 2023.03.15 |