JavaScript “this” 키워드 이해하기

자바스크립트에서 this 키워드는 정확히 무엇을 의미할까요? 그리고 자바스크립트 코드에서 실제로 어떻게 활용할 수 있을까요? 이러한 질문들은 자바스크립트를 처음 접하는 개발자뿐만 아니라 어느 정도 숙련된 개발자들 사이에서도 자주 등장하는 일반적인 질문들입니다.
혹시 여러분도 this 키워드의 의미가 궁금했던 개발자 중 한 명이라면, 이 글이 여러분에게 도움이 될 것입니다. 다양한 상황 속에서 this가 어떤 의미를 가지는지 자세히 알아보고, 혼란을 줄이고 코드 오류를 방지하는 데 필요한 지식을 쌓아보세요.
전역 범위 내에서의 this
전역 범위에서 this는 함수 외부에서 사용될 때 window 객체를 반환합니다. 즉, 전역 범위는 함수 내부에 위치하지 않는 영역을 의미합니다.
if(true) {
console.log(this)
}
let i = 2;
while(i < 10) {
console.log(this)
i++
}
위 코드의 실행 결과로 window 객체가 출력됩니다.
함수(메서드) 내부에서의 this
함수 내부에서 this를 사용하면 해당 함수가 속한 객체를 가리킵니다. 하지만 독립적으로 실행되는 함수에서 this를 사용할 경우에는 window 객체를 반환한다는 예외적인 상황도 존재합니다. 몇 가지 예시를 통해 더 자세히 알아보겠습니다.
다음 예시에서 sayName 함수는 me 객체 내부에 정의되어 있습니다. 이러한 경우, this는 함수를 포함하는 객체를 참조합니다.
function sayName() {
return `내 이름은 ${this.name}입니다`;
}
const me = {
name: "길동",
sayName: sayName
};
console.log(me.sayName());
여기서 this는 me 객체를 나타내므로, sayName 메서드 내에서 this.name을 호출하는 것은 me.name과 완전히 동일한 동작을 수행합니다.
다른 관점에서 생각해보면, 함수가 호출될 때 함수의 왼쪽에 있는 것이 무엇이든 간에 그것이 this가 된다고 볼 수 있습니다. 이것은 sayName 함수를 다른 객체에서 재사용할 수 있으며, 매번 완전히 다른 컨텍스트를 참조할 수 있음을 의미합니다.
앞서 언급했듯이, 독립적인 함수 내에서 사용될 때 this는 window 객체를 반환합니다. 이는 독립 실행형 함수가 기본적으로 window 객체에 바인딩되기 때문입니다.
function talk() {
return this;
}
talk();
talk()를 호출하는 것은 window.talk()를 호출하는 것과 동일하며, 함수 왼쪽에 있는 모든 것이 자동으로 this가 됩니다.
참고로, 함수의 this 키워드는 자바스크립트의 엄격 모드(strict mode)에서는 다르게 동작합니다(undefined를 반환). 이는 엄격 모드를 사용하는 UI 라이브러리(예: React)를 사용할 때에도 고려해야 할 사항입니다.
Function.bind()와 함께 this 사용
객체에 함수를 메서드로 추가할 수 없는 상황(마지막 섹션과 같이)이 있을 수 있습니다.
아마도 해당 객체가 여러분의 소유가 아니어서 외부 라이브러리로부터 가져와 사용 중일 수도 있습니다. 혹은 객체가 변경 불가능하여 수정할 수 없을 수도 있습니다. 이와 같은 경우에도 Function.bind() 메서드를 사용하여 객체와 분리된 함수를 실행할 수 있습니다.
다음 예시에서 sayName 함수는 me 객체의 메서드가 아니지만, bind() 함수를 사용하여 me 객체에 바인딩되었습니다.
function sayName() {
return `내 이름은 ${this.name}입니다`;
}
const me = {
name: "길동"
};
const meTalk = sayName.bind(me);
meTalk();
bind()에 전달된 객체는 해당 함수 호출에서 this의 값으로 사용됩니다.
요약하자면, 어떤 함수에서든 bind()를 사용하여 새로운 컨텍스트(객체)를 전달할 수 있으며, 전달된 객체가 해당 함수 내에서 this의 의미를 덮어씁니다.
Function.call()과 함께 this 사용
완전히 새로운 함수를 반환하는 대신 컨텍스트에 바인딩한 후 즉시 함수를 호출하고 싶다면 어떻게 해야 할까요? 이때는 call() 메서드를 사용하면 됩니다.
function sayName() {
return `내 이름은 ${this.name}입니다`;
}
const me = {
name: "길동"
};
sayName.call(me);
call() 메서드는 다른 함수를 반환하는 대신 함수를 즉시 실행합니다.
함수에 매개변수가 필요한 경우, call() 메서드를 통해 매개변수를 전달할 수 있습니다. 다음 예시에서는 언어 매개변수를 sayName() 함수에 전달하여 조건에 따라 다른 메시지를 반환할 수 있습니다.
function sayName(lang) {
if (lang === "ko") {
return `내 이름은 ${this.name}입니다`;
} else if (lang === "en") {
return `My name is ${this.name}`;
}
}
const me = {
name: "길동"
};
sayName.call(me, 'ko');
sayName.call(me, 'en');
보시다시피, 원하는 매개변수를 call() 메서드의 두 번째 인수로 전달할 수 있습니다. 필요한 만큼 여러 개의 매개변수를 전달할 수도 있습니다.
apply() 메서드는 call() 및 bind()와 매우 유사합니다. 유일한 차이점은 call()을 사용할 때 여러 인수를 쉼표로 구분하여 전달하는 반면, apply()를 사용할 때는 배열 내에 여러 인수를 전달한다는 것입니다.
요약하자면, bind(), call(), apply() 메서드는 모두 함수와 객체 사이에 아무런 관계가 없을 때(즉, 함수가 객체의 메서드가 아닐 때) 다른 객체를 사용하여 함수를 호출할 수 있도록 해줍니다.
생성자 함수 내부에서의 this
new 키워드를 사용하여 함수를 호출하면 this 객체가 생성되어 반환됩니다.
function Person(name){
this.name = name;
}
const me = new Person("길동");
const her = new Person("영희");
const him = new Person("철수");
me.name;
her.name;
him.name;
위 코드에서는 동일한 함수로 세 가지 다른 객체를 생성했습니다. new 키워드는 생성되는 객체와 함수 내부의 this 키워드 사이에 자동으로 바인딩을 생성합니다.
콜백 함수 내부에서의 this
콜백 함수는 일반 함수와는 다른 특징을 가지고 있습니다. 콜백 함수는 다른 함수의 인수로 전달되는 함수이므로, 기본적인 함수 실행이 완료된 직후에 실행될 수 있습니다.
this 키워드는 콜백 함수 내에서 사용될 때 완전히 다른 컨텍스트를 참조합니다.
function Person(name){
this.name = name;
setTimeout(function() {
console.log(this);
}, 1000);
}
const me = new Person("길동");
Person 생성자 함수를 호출하고 새로운 me 객체를 생성한 후, 1초가 지나면 window 객체가 this 값으로 출력됩니다. 따라서 콜백 함수에서 사용될 때 this는 "생성된" 객체가 아닌 window 객체를 참조합니다.
이 문제를 해결하는 방법에는 두 가지가 있습니다. 첫 번째 방법은 새로 생성된 객체에 콜백 함수를 바인딩하기 위해 bind()를 사용하는 것입니다.
function Person(name){
this.name = name;
setTimeout(function() {
console.log(this);
}.bind(this), 1000);
}
const me = new Person("길동");
위와 같이 수정하면 콜백 내에서 this는 생성자 함수(me 객체)와 동일한 this를 가리키게 됩니다.
콜백 함수에서 this 문제를 해결하는 두 번째 방법은 화살표 함수를 사용하는 것입니다.
화살표 함수 내부에서의 this
화살표 함수는 일반 함수와 다릅니다. 콜백 함수를 화살표 함수로 만들 수 있습니다. 화살표 함수를 사용하면 새로 생성된 객체에 자동으로 바인딩되므로 bind()를 더 이상 사용할 필요가 없습니다.
function Person(name){
this.name = name;
setTimeout(() => {
console.log(this);
}, 1000);
}
const me = new Person("길동");
자바스크립트에 대해 더 자세히 알아보기
이제 this 키워드에 대해 모두 배우셨습니다. 자바스크립트의 다양한 컨텍스트에서 this가 무엇을 의미하는지 알게 되었습니다. 자바스크립트를 처음 접하는 경우, 자바스크립트의 모든 기본 사항과 작동 방식을 배우면 큰 도움이 될 것입니다.