[코어 자바스크립트] 3장 this 👉

뉴우비(newwwbi)·2021년 9월 25일
0

아래의 내용은 정재남의 <코어 자바스크립트> 책을 공부하며 중요한 내용을 정리한 것입니다.



this

this는 자바스크립트에서 가장 헷갈리는 개념이다.
대부분의 객체지향 언어에서 this는 클래스에서만 쓰이며, 클래스로 생성한 인스턴스를 의미한다.
반면에 자바스크립트에서 this는 다양한 곳에서 쓰일 수 있으며, 상황에 따라서 그 의미가 제각각으로 달라진다.
this를 제대로 사용하기 위해서는 상황에 따라서 this의 의미가 어떻게 바뀌는지 잘 알고 있어야 한다.
this에 대해서 정리해보자.


전역 공간에서의 this

전역 공간에서 this는 전역 객체를 가리킨다.
전역 객체는 자바스크립트 실행 전에 생성되는 특수한 객체인데, 전역 변수나 전역 함수를 담는 공간 역할을 한다.
전역 객체는 자바스크립트 런타임 환경에 따라서 불리는 이름이 다르다.
브라우저에서는 window 이고, Node.js에서는 global 이다.
(전역 객체에 대한 설명은 2장 실행 컨텍스트를 읽고나서 보충하겠다)

내가 봤을 때 전역 공간에서 this를 사용해야 할 특별한 이유는 없는거 같다.
전역 공간에서 this를 사용하면 오히려 코드를 읽는 사람에게 혼란만 줄거 같다...


함수 호출 방식에 따라 달라지는 this

앞에서 this의 의미가 상황에 따라서 달라진다고 말했다.
좀 더 정확히 말하지만, this의 의미는 함수가 어떤 방식으로 호출되는지에 따라서 달라진다.
자바스크립트에서 this는 기본적으로 실행 컨텍스트가 생성될 때 결정되는데, 실행 컨텍스트는 함수를 호출할 때 생성된다.
그러므로 this는 함수가 호출될 때 결정된다고 할 수 있다.

함수를 일반 함수로서 호출할 때와 메서드로서 호출할 때 this의 의미는 다음과 같다.

  • 일반 함수로서 호출할 때 함수 내부의 this는 전역 공간에서의 this와 마찬가지로 전역 객체를 가리킨다.
  • 메서드로서 호출할 때 함수 내부의 this는 해당 메서드를 호출한 객체를 가리킨다.

함수 호출 방식에 따라서 this가 가리키는 대상이 명쾌하게 결정되는거 같지만, 가끔씩 헷갈릴 때가 있다.
아래의 예제 코드의 실행 결과는 각각 무엇일까?

예제 1

var a = 1;

var obj = {
   a: 2,
   func1: function() {
     console.log(this.a);
   },
};

var func2 = obj.func1;

func2(); // 1 or 2 ???

예제 2

// 예제 2
var a = 1;

var obj = {
   a: 2,
   outer: function() {
     var inner = function() {
       console.log(this.a);
     }

     inner(); // 1 or 2 ???
   },
};

obj.outer();





정답은 둘 다 1이다!!!

예제 1에서 func2는 일반 함수로서 호출되었기 때문에 func2 내부의 this는 전역 객체를 가리킨다.
그러므로 this.a를 콘솔에 표시한 결과는 1이다.

예제 2에서 outer 함수는 메서드로서 호출되었기 때문에 outer 내부의 this는 obj 객체를 가리킨다.
inner 함수는 outer 함수 내부에서 선언되고 호출되었기 때문에 inner 내부의 this도 obj 객체를 가리킬 거 같지만... 아니다!
inner 함수는 일반 함수로 호출되었고 inner 내부의 this는 전역 객체를 가리킨다.
그러므로 inner함수 내부에서 this.a를 콘솔에 표시한 결과도 1이다.


함수가 일반 함수로서 호출되었는지, 아니면 메서드로서 호출되었는지 쉽게 구분할 수 있는 방법이 있다.
함수 앞에 점(.)이 있는지 여부만 체크하면 된다!
함수 앞에 점이 없으면 일반 함수로서 호출된 것이고, 함수 앞에 점이 있으면 메서드로서 호출된 것이다.
예제 2에서 inner 함수 앞에는 점이 없다.
그러므로 inner 함수는 일반 함수로서 호출된 것이라고 판단하면 된다.
반면에 outer 함수 앞에는 점이 있다.
그러므로 outer 함수는 메서드로서 호출된 것이다.
outer 함수 내부의 this는 가장 마지막 점 앞에 명시된 객체, obj가 된다.


콜백 함수 내부의 this

그렇다면 콜백 함수 내부의 this가 가리키는 대상은 무엇일까?
콜백 함수 내부의 this가 가리키는 대상은 고정되어 있지 않다.
콜백 함수 내부의 this는 콜백 함수를 인자로 받은 함수의 내부 로직에 따라서 결정된다.
콜백 함수도 함수이기 때문에 기본적으로 콜백 함수 내부의 this는 전역 객체를 가리킨다.
하지만 콜백 함수를 인자로 받은 함수 내부에서 콜백 함수에 별도로 this를 바인딩하는 경우가 있다.
예를 들면, addEventListener 메서드는 콜백 함수의 this에 이벤트가 발생한 요소를 바인딩시킨다.

<!DOCTYPE html>
<html>
  <body>
    <input type="button" value="click" id="btn" />
    <script>
      var printThis = function() {
         console.log(this);
      };

      // id가 'btn' 인 HTML Element의 클릭 이벤트가 발생하면 printThis를 호출시킨다.
      document.getElementById('btn').addEventListener('click', printThis);
    </script>
  </body>
</html>

코드와 그림 출처: ursr.log


콜백 함수 내부에서 this를 출력해본 결과, 클릭 이벤트가 발생한 <input> element가 출력되었다.

그러므로 콜백 함수 내부의 this는 콜백 함수를 인자로 받은 함수마다 다르다고 할 수 있다.
하지만 addEventListener 메서드처럼 API 문서에 특별히 명시되어 있지 않은 경우, 콜백 함수 내부의 this는 전역 객체라고 생각해도 된다.



참고 자료

http://tcpschool.com/javascript/js_standard_object
https://velog.io/@ursr0706/이벤트-핸들러-내부의-this-2gyujqm2
https://developer.mozilla.org/ko/docs/Web/API/EventTarget/addEventListener#핸들러내부의_this

profile
배운 지식을 다른 사람과 공유하고 싶습니다

2개의 댓글

comment-user-thumbnail
2021년 10월 25일

this 전역개체를 가르킨다!? 라고 외워두면 괜찮을까요?
어렵네요...this

1개의 답글