[JavaScript] setTimeout() 의 this는 왜 다른가?

Bomin·2023년 10월 27일
0

[JavaScript]

목록 보기
6/6
post-thumbnail

💡 setTimeout()

지정한 시간 후 함수나 지정한 코드를 실행하는 타이머를 설정하는 비동기 메서드

  • setTimout에서 this는 항상 전역 객체(window)를 this 바인딩 한다.

💦 왜 그럴까?

  • 그 이유는 setTimeout이 실행되는 코드는 setTimeout을 호출했던 곳과는 다른 실행 컨텍스크(브라우저)에서 호출되기 때문이다.

  • 즉, 비동기 함수 호출의 동작방식, 이벤트 루프와 관련이 있다.

  • 호출 함수의 this 키워드 값을 설정하는 일반적인 규칙(객체의 메서드로서! - this는 . 앞의 객체를 가리킴)이 여기서도 적용되며, this를 호출 시 지정하지 않고, bind를 바인딩을 하지 않는 경우 window를 가리키게 된다.
    -> 콜백 함수가 호출된 환경인 window를 가리킨다.

const myArray = ['zero', 'one', 'two'];

myArray.myMethod = function (sProperty) {
  // this[sProperty]가 myArray[sProperty]와 동일함 확인
  console.log(arguments.length > 0 ? this[sProperty] : this);
};

// 여기서 this는 myArray
myArray.myMethod(); // [ 'zero', 'one', 'two', myMethod: [Function (anonymous)] ]
myArray.myMethod(1); // one
  • setTimeout을 사용해서 호출해보면
// 타이머 완료 후 호출 시점에 this가 따로 설정되지 않았기 때문 -> window
setTimeout(myArray.myMethod, 1.0 * 1000); // 1초 후, window  
setTimeout(myArray.myMethod, 1.5 * 1000, '1'); //1.5초 후, undefined
  • 타이머 완료 후 호출 시점에서 this가 따로 설정되지 않았기 때문에 this는 window를 가리킨다.

  • 배열의 1번째를 출력하고자 했지만, 타이머 완료 후 콜백 함수가 호출되는 환경에서는 myArray를 찾을 수 없었기 때문에 undefined가 출력된다.

  • 이를 해결하기 위해서 함수(화살표 함수, 익명함수 등)를 감싸서 해결할 수 있고, bind로 this 값을 설정할 수도 있다.

// 💡 해결법
// 1. 함수 감싸기
setTimeout(function () {
  myArray.myMethod();
}, 2.0 * 1000); // [ 'zero', 'one', 'two', myMethod: [Function (anonymous)] ]
setTimeout(function () {
  myArray.myMethod('1');
}, 2.5 * 1000); // one

// 2. 화살표 함수
setTimeout(() => {
  myArray.myMethod();
}, 2.0 * 1000); // [ 'zero', 'one', 'two', myMethod: [Function (anonymous)] ]
setTimeout(() => {
  myArray.myMethod('1');
}, 2.5 * 1000); // "one"

// 3. bind
const myBoundMethod = function (sProperty) {
  console.log(arguments.length > 0 ? this[sProperty] : this);
}.bind(myArray);

myBoundMethod(); //  [ 'zero', 'one', 'two', myMethod: [Function (anonymous)] ]
myBoundMethod(1); // one
setTimeout(myBoundMethod, 1.0 * 1000); // [ 'zero', 'one', 'two', myMethod: [Function (anonymous)] ]
setTimeout(myBoundMethod, 1.5 * 1000, '1'); // one

🔥 정리

  • setTimeout()에서 this는 전역 객체(window)를 가리킨다.
  • 비동기 함수 동작 방식에 의해 타이머 기능 수행 후 호출하는 시점에는 다른 실행 컨텍스트에 있기 때문에 window를 가리키는 것이다.
  • 이를 해결하기 위해서는 화살표 함수나 bind를 이용해 this를 고정해주자!

혼자 찾아보며 정리하고 이해한 내용입니다. 잘못된 부분이 있으면 알려주세요..🥺
https://ggodong.tistory.com/322
https://developer.mozilla.org/ko/docs/Web/API/setTimeout

profile
Frontend-developer

0개의 댓글