JS 6.3 · 6부. 객체지향과 모던 JS

this 이해하기

호출하는 방식에 따라 this 가 달라지는 것을 봅니다.

예상 학습 시간 15분 실행 단추가 있는 예제는 고쳐서 실행해 볼 수 있습니다 난이도 중급
개념 설명

this 는 부르는 방식이 정합니다

6.1 에서 this 를 "지금 그 객체" 라고 했습니다. 조금 더 정확히 말하면 this 는 함수를 어떻게 불렀는지에 따라 정해집니다. 함수를 어디에 적었는지가 아닙니다.

이 성질이 버그를 만듭니다. 화살표 함수는 그 문제를 피하려고 규칙이 다릅니다.

최소 예제 · 편집 가능

점 앞에 있는 것이 this 입니다

script.js
const counter = {
	count: 0,

	increase() {
		this.count++;
		return this.count;
	}
};

console.log(counter.increase());
console.log(counter.increase());
console.log(counter.count);
출력
1 2 2

counter.increase() 처럼 부르면 점 앞에 있는 것this 입니다.

상세 사용법

떼어내면 잃습니다

같은 함수를 변수에 담아 부르면 점 앞에 아무것도 없습니다. 그러면 this 도 그 객체가 아닙니다.

script.js
const counter = {
	count: 0,
	increase() {
		return ++this.count;
	}
};

console.log(counter.increase());

const increase = counter.increase;

console.log(increase());
console.log(counter.count);
출력
1 NaN 1

NaN 이 나왔고 counter 도 늘지 않았습니다. 떼어낸 함수의 thiscounter 가 아니라서, 없는 값에 1 을 더한 것입니다(1.6).

이 실수는 오류를 내지 않습니다. 값이 이상할 때까지 모릅니다. 함수를 넘길 일이 많은 4부·5부에서 자주 만납니다.

상세 사용법

붙여 두기

bindthis 를 정해 둔 새 함수를 만들어 줍니다.

script.js
const counter = {
	count: 0,
	increase() {
		return ++this.count;
	}
};

const bound = counter.increase.bind(counter);

console.log(bound());
console.log(bound());
console.log(counter.count);
출력
1 2 2
상세 사용법

화살표 함수는 다릅니다

화살표 함수는 자기 this 를 만들지 않습니다. 적힌 자리의 바깥 this 를 그대로 씁니다. 그래서 떼어내도 잃지 않습니다.

script.js
const timer = {
	name: "타이머",

	withFunction() {
		setTimeout(function () {
			console.log("보통 함수:", this === timer);
		}, 10);
	},

	withArrow() {
		setTimeout(() => {
			console.log("화살표:", this === timer);
		}, 10);
	}
};

timer.withFunction();
timer.withArrow();
출력
보통 함수: false 화살표: true

setTimeout 은 넘겨받은 함수를 점 없이 부릅니다(5.1). 보통 함수는 그때 this 를 잃고, 화살표 함수는 withArrow 안의 것을 그대로 씁니다.

다른 함수에 넘길 함수는 화살표로 적으세요. 4.5 의 addEventListener 도 같습니다.

상세 사용법

메서드는 화살표로 적지 않습니다

반대로 객체의 메서드 자체를 화살표로 적으면 안 됩니다. 바깥에는 그 객체가 없기 때문입니다.

script.js
const wrong = {
	count: 10,
	read: () => this === wrong
};

const right = {
	count: 10,
	read() { return this === right; }
};

console.log(wrong.read());
console.log(right.read());
출력
false true

정리하면 이렇습니다. 메서드는 보통 함수로, 넘길 함수는 화살표로.

흔한 실수

처음에 자주 걸리는 것

1. 메서드를 그대로 넘깁니다

setTimeout(counter.increase, 100) 은 점 없이 불립니다. bind 하거나 화살표로 감싸세요.

setTimeout(counter.increase, 100);          // this 를 잃습니다
setTimeout(() => counter.increase(), 100);  // 이렇게 적습니다
2. 객체 메서드를 화살표로 적습니다

바깥에 그 객체가 없어 this 가 엉뚱한 것을 가리킵니다. 클래스 메서드도 마찬가지입니다.

3. 오류가 나기를 기다립니다

this 를 잃어도 대개 오류가 아니라 undefinedNaN 이 나옵니다. 값이 이상하면 이것을 먼저 의심하세요.

실습 문제

직접 해보기

1. 결과 예측하기 난이도 하

아래 두 줄의 결과를 먼저 적어 보고 확인하세요.

const user = { name: "홍길동", greet() { return `${this.name}님`; } }; const greet = user.greet; console.log(user.greet()); console.log(greet());
첫 줄은 홍길동님, 둘째 줄은 this 를 잃어 이름이 비어 있습니다.
2. 잃지 않게 고치기 난이도 중

아래 코드는 0.1초 뒤 이름을 출력하려 했는데 그러지 못합니다. 두 가지 방법으로 고쳐 보세요.

const user = { name: "홍길동", later() { setTimeout(function () { console.log(this.name); }, 100); } }; user.later();
// 방법 1 — 화살표 함수로 const withArrow = { name: "홍길동", later() { setTimeout(() => console.log(this.name), 100); } }; // 방법 2 — bind 로 const withBind = { name: "김철수", later() { setTimeout(function () { console.log(this.name); }.bind(this), 100); } }; withArrow.later(); withBind.later();
요약

이 단원의 정리

  • this 는 함수를 어떻게 불렀는지가 정합니다.
  • 객체.메서드() 로 부르면 점 앞의 것이 this 입니다.
  • 떼어내 부르면 잃습니다. 오류가 나지 않아 알아채기 어렵습니다.
  • 화살표 함수는 자기 this 를 만들지 않고 바깥 것을 씁니다.
  • 메서드는 보통 함수로, 넘길 함수는 화살표로 적습니다.