서론
자바스크립트의 this는 다른 언어의 this와 달리 좀 변덕(?)스럽게 느껴질 수 있습니다. 어디서 어떻게 쓰이냐에 따라서 개발자의 생각과는 다른 녀석을 가르키고 있을 수 있거든요.이번 블로그에서는 자바스크립트의 this가 어떻게 작동하는 지 그리고 주의해야될 사례들에 대해 소개하며 this 교통정리 좀 해보도록 하겠습니다.
목록
- 기본사용
- 일반함수
- 객체 내 메소드로 사용될 때
- 콜백함수의 this
- 생성자
- 화살표 함수
- 이벤트 리스너
기본사용
자바스크립트에서 this는 대부분의 경우 함수가 어디서 호출되었는가에 따라 결정됩니다. 이 말은 this가 포함된 함수가 어디서 또는 어떻게 사용되느냐에 따라 가리키는 대상이 달라지게 된다는 걸 의미합니다. 이 내용이 this의 핵심이기 때문에 꼭 기억하셔야 됩니다.
예를들어, JS에서 일반적으로 this를 호출한다면 아래와 같이 this는 window를 가리킵니다. 왜냐하면 이때, this는 window라는 객체에서 호출됬기 때문이죠.
참고로, window는 html 태그, JS 변수, 객체 등을 모두 포함하는 최상위 전역객체 입니다.
console.log(this); // Window
일반함수
일반적으로 선언된 함수도 window 객체에서 호출했으니 this는 window를 가르킵니다(또는 바인딩 되어있다고 표현), 일반함수 내부에 선언된 함수의 this도 window를 지칭하는 걸 볼 수 있습니다.
(단, 엄격모드에서는 함수내 디폴트 바인딩이 없기 때문에 일반함수의 this는 undefined입니다.)
// 일반함수와 일반함수 속에서 선언된 함수의 this
function Func() {
console.log(this); //Window
function InnerFunc(){
console.log(this); //Window
}
InnerFunc();
}
Func();
객체 내 메소드로 사용될 때
이제 this가 가르키는 대상이 바뀌기 시작합니다. 아래 코드와 같이 object의 메소드 속 this는 object를 가르킵니다.
// object 메소드 속 this
let obj = {
firstName: 'John',
lastName: 'Doe',
objMethod: function () {
console.log(this); // obj를 가르킴, {firstName: 'John', lastName: 'Doe', getFullName: ƒ}
console.log(this.firstName); // John
console.log(this.lastName); // Doe
},
};
obj.objMethod();
만약 위에서 정의한 메소드를 object 바깥으로 끌고나오면 this는 window를 가르키게 됩니다. 이젠 obj의 메소드로 호출된 것이 아니라 window객체에서 호출된 거니깐요. window.firstName과 window.lastName는 할당받은 값이 없으니 모두 undefined가 뜨는 걸 볼 수 있습니다.
// 오브젝트 메소드 외부로 갖고 나왔을 때 this 변경(obj -> window)
const a = obj.objMethod;
a(); // this는 window를 가르키고, this.firstName, this.lastName은 undefined
콜백함수의 this
여기서, 주의할 점이 있습니다. 아래 코드와 같이 메소드의 콜백함수 this는 object를 가르키는 게 아닌 window를 가르킵니다. 콜백함수로 호출될 때, 일반함수로서 호출되게 되고 this는 window를 가르키기 때문입니다.
(참고: object의 메소드 자체가 다른 곳의 콜백함수로 쓰이게 될 때에도 마찬가지 입니다. 이때도 콜백함수로 호출되게 되면 메소드가 아닌 일반함수로서 호출되기 때문입니다.)
// setTimeout의 파라미터로 쓰인 콜백함수의 this는 window를 가르킨다
var object = {
setTime: setTimeout(function () {
console.log(this); // Window
}, 3000),
};
object.setTime;
생성자
생성자를 통해 만들어지는 인스턴스 객체와 this가 바인딩됩니다. 자세히는 new 키워드로 생성자가 실행될 때, 인스턴스 객체를 this에 할당합니다. 아래는 클래스 예시입니다.
// 생성자 this, 클래스 예시
//클래스 선언
class Car {
constructor(price, color) {
this.price = price;
this.color = color;
}
showThis() {
console.log(this);
}
}
// 인스턴스 생성 1
const redCar = new Car(50000, 'red'); // 생성된 인스턴스가 this에 할당 됩니다.
console.log(redCar.price); // 50000
console.log(redCar.color); // red
redCar.showThis(); // Car {price: 50000, color: 'red'}
// 인스턴스 생성 2
const blueCar = new Car(30000, 'blue'); // 생성된 인스턴스가 this에 할당 됩니다.
console.log(blueCar.price); // 30000
console.log(blueCar.color); // blue
blueCar.showThis(); // Car {price: 30000, color: 'blue'}
화살표함수의 this
function 키워드로 생성된 함수와 화살표 함수에서 사용된 this는 다릅니다. 위에서 함수와 메소드들의 예시에서, this는 어디서 호출되었느냐에 따라 바인딩 되는 객체가 결정되었습니다(동적으로 결정). 하지만, 화살표 함수의 this는 언제나 상위스코프의 this를 가르킵니다. 즉, 화살표 함수를 선언할 때 this와 바인딩되는 객체가 정적으로 결정됩니다.
// a: 일반적으로 쓰인 this
// b: 객체 메소드(function 키워드로 생성) 안에서 쓰인 this
// c: 화살표 함수안에서 쓰인 this
var obj = {
a: console.log(this),
b: function () {
console.log(this);
},
c: () => {
console.log(this);
},
};
obj.a; // window
obj.b(); // obj
obj.c(); // window
위 코드를 보면 화살표 함수의 상위 스코프는 window이므로 화살표 함수의 this는 window를 가르킵니다.
이벤트 리스너
이거는 별도로 외워야 되는 특징입니다. 아래 코드같이 onclick 같은 이벤트가 발생했을 때, 내부적으로 this는 이벤트가 발생한 html요소 자체와 바인딩 됩니다.
<!-- DOM 요소와 바인딩된 this 예제 -->
<!-- click 이벤트 예시, 이벤트가 발생된 html요소 자체를 가리킴, 여기서는 button태그 자체를 가르킴 -->
<button onclick="myFunction(this);">클릭</button>
<script>
function myFunction(obj) {
console.log(obj); // <button>
}
</script>
결론
자바스크립트에서 this는 사용방법에 따라 개발자에게 혼란을 줄 수 있습니다. 작성을 하다보니 this의 사용예시를 한 개씩 나열을 한 것처럼 보이지만, 정리를 해보면 메인이 되는 내용이 있고 그 외 곁 가지 예외가 되는 내용으로 이뤄집니다.
정리를 하면, 아래와 같습니다
[중심이 되는 내용]
1. this는 객체 또는 인스턴스를 지칭하는 데, 함수를 어디서 어떻게 호출했는 지에 따라 결정이 된다.
- 일반함수
- object 메소드
- 생성자
- 콜백함수
[예외사항]
2. 화살표 함수는 정적 바인딩이므로, 가장 가까운 상위 this를 지칭한다.
3. 이벤트리스너의 경우 이벤트가 발생할 때 this는 이벤트가 발생한 DOM요소를 지칭한다.
'코딩기록 > JavaScript' 카테고리의 다른 글
[JavaScript]얕은 복사, 깊은 복사 이해하기 (0) | 2023.01.08 |
---|---|
[JavaScript] 웹 스토리지 알아보기 - local storage, session storage (1) | 2022.12.31 |
[JavaScript] Date 객체 (0) | 2022.12.11 |
[JavaScript]for 반복문 정리(for, for in, for of, forEach) (0) | 2022.12.02 |