자바스크립트에서 this는 참으로 어려운 개념이다.
this가 호출될 때, 호출되는 대상에 따라서 참조하는 범위가 동적으로 바뀌기 때문이다.
- 메서드로써 호출되면 본인을 호출한 메서드를 가지고 있는 객체를 참조한다. (Array라던지, Object라던지..)
- 함수 내 함수로써 호출되면 전역을 참조하거나(선언형), 위 스코프를 참조(화살표형)한다.
메서드로써의 this는 무엇을 참조할까?
;[5, 6, 7].push(10)
// push 메서드 내부의 this는 `.`뒤의 배열([5, 6, 7])을 참조하게 된다.
const a = [1, 2, 3]
a.getLast()
// getLast 메서드 내부의 this는 `.`뒤의 배열([1, 2, 3])을 참조하게 된다.
alert('안녕하세요.')
// `.` 뒤에 아무 연결점이 없다면 this는 어디를 참조하게 될까?
/*
메서드를 호출할 때 `.`이 없다면
브라우저 환경에서 this는 전역객체인 window를 참조하여
window.alert('안녕하세요.') 형식으로 참조하게 될 것이고,
NodeJS 환경에서 this는 전역객체인 global를 참조하여
global.alert('안녕하세요.') 형식으로 참조하게 될 것이다.
*/
this는 메서드로써 호출되면 본인을 호출한 메서드를 가지고 있는 객체를 참조한다.
본인을 호출한 대상이 없으면 window나 global을 참조한다.
함수가 함수를 호출했을 경우(ex. 콜백함수) this는 무엇을 참조할까?
setTimeout(function () {
console.log(this) // What is this? Answer below
})
위의 경우, setTimeout 자체가 누군가 만들어준 함수이기 때문에,
this가 무엇을 참조할지는 고려를 해보아야 한다.
setTimeout은 아래와 같이 동작하여, 살짝 꼬아있기 때문이다.
const setTimeout = function (func) => {
const newObject = {}
newObject.func = func // 파라미터에 할당받은 input 함수를 새로운 객체에 할당한다.
newObject.func()
// 만들어낸 메서드를 실행한다. 이 상황에서 this가 있다면
// this는 본인을 호출한 객체인 newObject를 참조하게 될 것이다.
}
그렇다면, 아래 코드의 경우는 무슨 값이 출력이 될까?
const arr = [5, 6, 7]
Array.prototype.delayedLast = function() {
setTimeout(function() {
console.log(this[this.length - 1])
}, 1000)
}
- undefined를 console.log에 띄운다.
- 이유는 setTimeout은 본인만의 새로운 객체를 만들어내며, 그 객체 내에서 콜백함수를 실행하기 때문에 this는 결국 아무것도 없는 setTimeout의 객체를 탐색하게 되어 최종적으로 undefined를 console.log에 띄운다.
위 현상을 막기 위해서는 함수가 함수를 호출하는 환경을 만들기전에
미리 this를 변수에 할당하는 방법이 있다.
const arr = [1, 2, 3]
Array.prototype.delayedLast = function() {
const self = this
setTimeout(function() {
console.log(self[self.length - 1])
}, 1000)
}
arr.delayedLast()
self라는 변수에 객체가 직접 호출한 메서드의 this를 할당시켜놓기 때문에
참조값이 공유되어 정상적으로 동작함을 알 수 있다.
함수가 함수를 호출했을 때 this를 편하게 사용하게 만들어주는 애로우 펑션
- 화살표 함수는 위의 현상을 해결하기위해 나왔다.
- 화살표함수 내부의 this는 사실상, 선언자체도 안되어있다.
- 이러한 특성때문에 this를 화살표 내부에서 만나게 되면, 상위 스코프의 변수를 찾는 자바스크립트의 성질에 따라
- 윗 스코프의 this를 참조하게 된다.
const arr = [1, 2, 3]
Array.prototype.delayedLast = function() {
setTimeout(() => {
console.log(this[this.length - 1])
}, 1000)
}
arr.delayedLast()
- 화살표 함수 내부는 this라는 것 자체가 존재하지 않아서
- 그냥 윗 스코프를 쭉 따라 참조값을 따온다.
'Javascript' 카테고리의 다른 글
간단 Jest 라이브러리 사용방법 (feat. TDD) (2) | 2022.10.21 |
---|---|
의도적으로 콜백지옥 만들기 (0) | 2022.10.19 |
reduce 심화 학습 (오브젝트에 reduce 활용하기) (0) | 2022.10.13 |
new 키워드 (0) | 2022.10.12 |
(문제) 오브젝트 내 가장 긴 문자열 value를 가진 key를 출력하기 (0) | 2022.10.05 |