본문으로 건너뛰기

메서드와 this

자바스크립트 목차클로저와 클래스레슨 52 / 76

목차

클래스와 new에서는 인스턴스를 만든 뒤 minji.stamps += 1처럼 밖에서 속성을 직접 고쳤습니다. 도장을 찍거나 개수를 올리는 동작을 **클래스 안의 함수(메서드)**로 넣어 두면, card.add()나 c.up()처럼 점(.)을 찍어 부르기만 해도 그 객체 자신의 속성을 읽고 바꿀 수 있습니다. 이때 메서드 안에서 **"지금 점 앞에 있는 그 객체"**를 가리키는 이름표가 바로 **this**입니다.

10단계 중 1단계. 11번 줄의 `new Counter(0)`이 `count: 0`이 든 `Counter` 객체 ①을 만들고 전역 이름표 `c`에 붙입니다.

1클래스 안에 메서드 적기와 this

클래스 중괄호 안에서는 function 키워드 없이 이름() { ... } 꼴로 **메서드(method)**를 적습니다.

class Counter {
  constructor(start) {
    this.count = start;
  }
  up() {
    this.count += 1;
    return this.count;
  }
}

이어서 Counter 인스턴스를 만들고 c.up()을 두 번 부릅니다.

const c = new Counter(0);
console.log(c.up());
console.log(c.up());
실행 결과
1
2

함수 만들고 부르기의 규칙 5에 this 규칙 한 줄이 더해집니다.

규칙 5(this) — 객체.메서드()처럼 점(.)으로 함수를 부르면, 새로 열린 호출 칸의 this 이름표가 점 앞의 객체에 붙는다.

  1. 첫 번째 c.up()을 부르면 up 호출 칸이 열리고, 점 앞이 c이므로 그 칸의 this가 c(객체 ①)를 가리킵니다.
  2. this.count += 1은 this 화살표를 따라가 객체 ①의 count를 0에서 1로 바꾸고, return this.count가 1을 돌려줍니다.
  3. 두 번째 c.up()을 부르면 다시 새 up 호출 칸이 열리고, this가 같은 객체 ①을 가리켜 count를 1에서 2로 올립니다.

2점 앞의 객체가 바뀌면 this도 그 객체를 가리킨다

up() 메서드는 코드에 한 번만 적혀 있지만, 부를 때마다 점 앞에 누가 있느냐에 따라 this가 가리키는 객체가 달라집니다.

class Counter {
  constructor(start) {
    this.count = start;
  }
  up() {
    this.count += 1;
  }
}

이어서 두 인스턴스 a, b를 만들고 a.up()만 부릅니다.

const a = new Counter(0);
const b = new Counter(10);
a.up();
console.log(a.count, b.count);
실행 결과
1 10

a.up()을 부를 때는 점 앞이 a이므로 this가 a의 객체를 가리켜 a.count만 1이 됩니다. b의 객체는 건드리지 않았으므로 b.count는 10 그대로입니다.

일반 객체 리터럴({ ... }) 안에 메서드를 넣었을 때도 규칙은 똑같습니다.

const card = {
  stamps: 1,
  add() {
    this.stamps += 1;
  },
};
card.add();
console.log(card.stamps);
실행 결과
2

card.add()의 점 앞이 card이므로 add 호출 칸의 this가 card 객체를 가리킵니다.

3메서드 안에서 this.를 빠뜨리면 왜 오류가 날까

메서드 안에서 객체의 속성을 읽거나 바꿀 때 this.를 빠뜨리면 어떻게 될까요? 먼저 결과를 맞혀 보세요.

class Counter {
  constructor(start) {
    this.count = start;
  }
  up() {
    count += 1;
  }
}
const c = new Counter(0);
c.up();

c.count가 1이 될까요, 아니면 오류가 날까요?

실행 결과 보기
실행 결과
main.js:6    count += 1;    ^ ReferenceError: count is not defined    at Counter.up (main.js:6:5)    at main.js:10:3

자바스크립트에서 점 없는 이름 count는 객체의 속성이 아니라 호출 칸의 변수 이름입니다(블록과 함수 안의 이름의 규칙 7). up 호출 칸에도, 전역 칸에도 count라는 변수는 없으므로 ReferenceError가 납니다. 객체 안의 count 속성을 찾아가려면 반드시 **this.count**라고 적어야 합니다.

예제

플로우 카페의 StampCard 클래스에 도장을 찍는 add() 메서드와 현재 도장 수를 돌려주는 info() 메서드를 넣어 보겠습니다.

class StampCard {
  constructor(owner) {
    this.owner = owner;
    this.stamps = 0;
  }
  add() {
    this.stamps += 1;
  }
  info() {
    const name = this.owner;
    const s = this.stamps;
    return `${name}: ${s}`;
  }
}

이어서 민지의 카드를 만들고 도장을 두 번 찍어 봅니다.

const c = new StampCard('민지');
c.add();
c.add();
console.log(c.info());
실행 결과
민지: 2

c.add()와 c.info() 모두 점 앞이 c이므로, 각 메서드 호출 칸의 this가 민지의 StampCard 객체를 가리켜 stamps를 2로 올리고 '민지: 2'를 돌려줍니다.

자주 틀리는 곳

1. 메서드 안에서 this.를 빠뜨림

파이썬과 달리 자바스크립트도 객체 속성을 가리킬 때는 this.를 생략할 수 없습니다. this.stamps 대신 stamps만 적으면 변수 이름을 찾다가 ReferenceError 오류가 납니다.

2. 괄호 없이 c.up만 적음

함수 만들고 부르기에서 배웠듯 함수 이름 뒤에 괄호 ()를 붙여야 함수가 불립니다. console.log(c.up)처럼 괄호를 빼면 메서드가 실행되지 않고 함수 값 자체가 찍힙니다.

class Counter {
  up() {
    return 1;
  }
}
const c = new Counter();
console.log(c.up);
실행 결과
[Function: up]

3. this가 메서드를 정의한 자리에 늘 묶여 있다고 생각함

this는 메서드를 어디에 적었느냐가 아니라 부르는 순간 점(.) 앞에 누가 있느냐로 정해집니다. 메서드를 변수에 꺼내 점 없이 부르면 this를 잃어버리는데, 이 현상은 바로 다음 레슨(this를 잃을 때)에서 자세히 다룹니다.

확인 문제

문제 1

다음 코드를 실행했을 때 출력되는 결과를 쓰세요.

class Point {
  constructor(x) {
    this.x = x;
  }
  move(step) {
    this.x += step;
  }
}

이어서 두 점 p1, p2를 만들고 움직입니다.

const p1 = new Point(10);
const p2 = new Point(50);
p1.move(5);
p2.move(20);
console.log(p1.x, p2.x);
힌트

p1.move(5)에서는 this가 p1을 가리키고, p2.move(20)에서는 this가 p2를 가리킵니다.

정답
실행 결과
15 70

p1.x는 10 + 5로 15가 되고, p2.x는 50 + 20으로 70이 됩니다.

문제 2

음료 가격 price에서 할인 금액 off를 빼는 cut(off) 메서드가 동작하도록 빈칸 ____ 두 곳을 채우세요.

class Drink {
  constructor(price) {
    this.price = price;
  }
  cut(off) {
    ____.price -= off;
    return ____.price;
  }
}

const d = new Drink(4500);
console.log(d.cut(500));
힌트

d.cut(500)을 불렀을 때 점 앞의 d 객체를 가리키는 이름표는 this입니다.

정답
  • 첫째 빈칸: this
  • 둘째 빈칸: this
class Drink {
  constructor(price) {
    this.price = price;
  }
  cut(off) {
    this.price -= off;
    return this.price;
  }
}

const d = new Drink(4500);
console.log(d.cut(500));
실행 결과
4000

문제 3

시작 잔액 balance를 받아 저장하는 constructor(balance)와, 금액 amount를 받아 잔액에 더하고 새 잔액을 돌려주는 deposit(amount) 메서드를 가진 Wallet 클래스를 직접 쓰세요.

기대 출력과 시험 값은 다음과 같습니다.

1500
1800
// 여기에 Wallet 클래스를 쓰세요

const w = new Wallet(1000);
console.log(w.deposit(500));
console.log(w.deposit(300));
힌트

deposit(amount) 메서드 안에서 this.balance += amount;⁠로 잔액을 올린 뒤 return this.balance;를 적습니다.

정답
class Wallet {
  constructor(balance) {
    this.balance = balance;
  }
  deposit(amount) {
    this.balance += amount;
    return this.balance;
  }
}

const w = new Wallet(1000);
console.log(w.deposit(500));
console.log(w.deposit(300));
실행 결과
1500
1800

컴퓨터에서 해 보기(선택) — 1절의 Counter 코드에서 up() 안의 this.count += 1;을 count += 1;로 바꿔 돌려 보세요. 3절에서 본 ReferenceError 오류가 나는 것을 확인한 뒤 다시 this.를 붙여 보세요.

끝까지 내려오면 저절로 표시됩니다. 이 기기에만 저장합니다.

자바스크립트 목차로