객체: 이름 붙은 칸 묶음에서는 { owner: '민지', stamps: 0 }처럼 중괄호로 객체를 하나씩 직접 적었습니다. 손님이 열 명이면 같은 모양의 객체를 열 번 반복해 적어야 하고, 속성 이름을 오타 내기도 쉽습니다. **class(클래스)**로 객체의 틀을 한 번 정의해 두면, new 연산자로 부를 때마다 같은 속성 구성을 가진 새 객체(인스턴스)를 찍어 낼 수 있습니다.
1class와 new — 같은 모양의 객체를 찍어 내는 틀
클래스는 class 뒤에 이름(보통 첫 글자를 대문자로 적습니다)과 중괄호를 써서 정의합니다. 중괄호 안의 **constructor(생성자)**는 new로 새 객체를 만들 때 자동으로 불리는 초기화 함수입니다.
class Counter {
constructor(start) {
this.count = start;
}
}
const a = new Counter(0);
const b = new Counter(10);
console.log(a.count, b.count);
0 10new Counter(0)을 실행하면 세 가지 일이 차례로 일어납니다(함수 만들고 부르기의 규칙 5 확장).
- 빈
Counter객체 ①이 새로 만들어집니다. constructor호출 칸이 열리고, 그 칸의this이름표가 방금 만든 빈 객체 ①을 자동으로 가리킵니다. 인자0은 매개변수start에 붙습니다.this.count = start가 실행되어this가 가리키는 객체 ① 안에count: 0속성을 채웁니다.constructor가 끝나면return을 적지 않아도 객체 ①이 자동으로 돌아와a에 붙습니다.
이어서 8번 줄에서 new Counter(10)을 부르면 두 번째 Counter 객체 ②가 따로 만들어지고, 그때의 this는 객체 ②를 가리킵니다. 이렇게 클래스로 만든 객체를 그 클래스의 **인스턴스(instance)**라고 부릅니다.
2고정된 첫 값은 클래스 필드로도 적는다
플로우 카페의 스탬프 카드를 클래스로 만들어 보겠습니다. 손님 이름(owner)은 카드를 만들 때마다 다르지만, 처음 도장 개수(stamps)는 늘 0에서 시작합니다.
class StampCard {
constructor(owner) {
this.owner = owner;
this.stamps = 0;
}
}
const c = new StampCard('민지');
console.log(c.owner, c.stamps);
민지 0늘 같은 값(0)으로 시작하는 속성은 constructor 밖 맨 위에 stamps = 0;처럼 바로 적어도 됩니다. 이 표기를 **클래스 필드(class field)**라고 합니다.
class StampCard {
stamps = 0;
constructor(owner) {
this.owner = owner;
}
}
const c = new StampCard('민지');
console.log(c.owner, c.stamps);
민지 0Node에서 인스턴스 자체를 console.log로 찍으면 앞에 클래스 이름과 함께 속성들이 중괄호로 묶여 출력됩니다.
class Card {
constructor(owner) {
this.owner = owner;
}
}
const c = new Card('민지');
console.log(c);
Card { owner: '민지' }3new를 두 번 부른 것과 이름만 하나 더 붙인 것
객체를 넘기고 복사하기에서 배운 규칙 3은 클래스로 만든 인스턴스에도 그대로 적용됩니다. 다음 코드의 출력을 먼저 맞혀 보세요.
class Counter {
constructor(start) {
this.count = start;
}
}
이어서 a, b, same을 만들고 a.count를 1로 바꿉니다.
const a = new Counter(0);
const b = new Counter(0);
const same = a;
a.count = 1;
console.log(b.count);
console.log(same.count);
b.count와 same.count는 각각 얼마가 찍힐까요?
실행 결과 보기
0
1const b = new Counter(0)은new를 다시 불렀으므로a(객체 ①)와 별개인 새 객체 ②를 만듭니다.a.count를 바꿔도b.count는0그대로입니다.const same = a는new를 부르지 않고a가 가리키던 같은 객체 ①에same이라는 이름표만 하나 더 붙인 것입니다. 따라서same.count로 읽으면 바뀐1이 나옵니다.
또한 클래스를 부를 때 new를 빠뜨리고 일반 함수처럼 Counter(0)만 부르면 바로 TypeError가 납니다.
class Counter {
constructor(start) {
this.count = start;
}
}
const a = Counter(0);
main.js:6const a = Counter(0); ^ TypeError: Class constructor Counter cannot be invoked without 'new' at main.js:6:11예제
플로우 카페 손님 두 명('민지', '준호')의 스탬프 카드를 각각 만들고, 민지의 카드에만 도장 1개를 찍어 두 카드가 서로 섞이지 않는지 확인해 보겠습니다.
class StampCard {
constructor(owner) {
this.owner = owner;
this.stamps = 0;
}
}
이어서 카드 두 장을 만들고 민지의 도장 수를 올립니다.
const c1 = new StampCard('민지');
const c2 = new StampCard('준호');
c1.stamps += 1;
console.log(c1.stamps);
console.log(c2.stamps);
1
0new StampCard(...)를 두 번 불렀으므로 c1과 c2는 서로 다른 두 객체를 가리킵니다. c1.stamps를 1로 올려도 c2.stamps는 0 그대로입니다.
자주 틀리는 곳
1. new를 빠뜨리고 클래스를 일반 함수처럼 부름
클래스 생성자는 new 없이 부를 수 없습니다. StampCard('민지')처럼 new를 빼고 쓰면 TypeError 오류가 납니다.
2. constructor 안에서 this.를 빠뜨림
constructor 안에서 새 객체에 속성을 넣으려면 꼭 this.stamps = 0;처럼 this.를 붙여야 합니다. let이나 this. 없이 stamps = 0;만 적으면 선언하지 않은 변수에 대입하려 한 것으로 보아 ReferenceError가 납니다.
class StampCard {
constructor(owner) {
this.owner = owner;
stamps = 0;
}
}
const c = new StampCard('민지');
main.js:4 stamps = 0; ^ ReferenceError: stamps is not defined at new StampCard (main.js:4:12) at main.js:7:113. 클래스 자체에서 인스턴스 속성을 읽으려 함
StampCard는 객체를 찍어 내는 틀일 뿐 아직 찍어 낸 카드가 아닙니다. new StampCard('민지')로 인스턴스를 만든 뒤 그 인스턴스(c1.stamps)에서 속성을 읽어야 합니다.
확인 문제
문제 1
다음 코드를 실행했을 때 출력되는 결과를 쓰세요.
class Box {
constructor(qty) {
this.qty = qty;
}
}
이어서 상자 두 개를 만들고 값을 바꿉니다.
const x = new Box(3);
const y = new Box(3);
x.qty += 2;
console.log(x.qty, y.qty);
힌트
new Box(3)을 두 번 불렀으므로 x와 y는 서로 다른 두 Box 객체를 가리킵니다.
정답
5 3x가 가리키는 첫 번째 상자의 qty만 3에서 5로 바뀌고, y가 가리키는 두 번째 상자의 qty는 3 그대로입니다.
문제 2
메뉴 이름 name과 가격 price를 받아 저장하는 Menu 클래스를 완성하고, '커피', 4000으로 새 인스턴스를 만들도록 빈칸 ____ 두 곳을 채우세요.
class Menu {
constructor(name, price) {
____.name = name;
this.price = price;
}
}
const m =
____ Menu('커피', 4000);
console.log(m.name, m.price);
힌트
constructor 안에서 새로 만들어진 객체를 가리키는 이름표는 this이고, 클래스로 새 객체를 만들 때는 앞에 new를 붙입니다.
정답
- 첫째 빈칸:
this - 둘째 빈칸:
new
class Menu {
constructor(name, price) {
this.name = name;
this.price = price;
}
}
const m =
new Menu('커피', 4000);
console.log(m.name, m.price);커피 4000문제 3
주인 이름 owner와 초기 잔액 money를 받아 속성에 저장하는 Wallet 클래스를 직접 쓰세요.
기대 출력과 시험 값은 다음과 같습니다.
민지
5000
// 여기에 Wallet 클래스를 쓰세요
const w =
new Wallet('민지', 5000);
console.log(w.owner);
console.log(w.money);
힌트
class Wallet 안에 constructor(owner, money)를 만들고 this.owner = owner;와 this.money = money;를 적습니다.
정답
class Wallet {
constructor(owner, money) {
this.owner = owner;
this.money = money;
}
}
const w =
new Wallet('민지', 5000);
console.log(w.owner);
console.log(w.money);민지
5000컴퓨터에서 해 보기(선택) — 1절 코드에서 const a = new Counter(0);의 new를 지우고 돌려 보세요. 어떤 오류 메시지가 몇 번 줄에서 나오는지 확인한 뒤 다시 new를 붙여 고쳐 보세요.