자바스크립트 this 바인딩이란?

이정민 Lee Jeong Min·2021년 2월 22일
4

Javascript

목록 보기
4/10

this와 실행 컨텍스트

자바스크립트는 스크립트 언어로, 인터프리터에 의해 줄 단위로 읽혀서 해석되어 실행된다.

인터프리터에 의해 현재 실행되는 자바스크립트의 환경을 실행 컨텍스트라고 한다. 자바스크립트 내부에서 이러한 실행 컨택스트를 스택으로 관리하며, 실행되는 시점에 자주 변경되는 실행 컨택스트를 this가 가리킨다.

즉, this는 현재 실행되는 코드의 실행 컨텍스트를 가리킨다.
Function.prototype 객체의 메서드인 call, apply, bind를 통해 명시적으로 this를 바인딩해줄 수도 있다.

binding 종류

1. default

기본적으로 this는 전역객체를 가리킨다. node환경에서는 global 객체를, 브라우저에서는 window 객체를 가리킨다.

2. 일반 함수 내부

일반적인 함수 내부에서 this를 호출하면 전역객체를 가리키는데,
strict 모드를 사용하는 경우에는 그렇지 않다.(undefined 반환)
즉시 실행함수의 경우에도 마찬가지이다.

3. 객체의 메소드 내부

객체 내부의 메소드 내부에서 this를 호출하면 해당 객체를 가리킨다. 이 경우 주의해야 할 점이 있는데,

1. 메소드 내부의 함수 내부에서 호출할 경우, 이는 함수 내부에서 호출한 것이 되어 전역객체를 가리키게 된다.

var obj = {
    print: function() {
      console.log(this); // obj 객체
      
      var print2 = function() {
        console.log(this); // window 객체
      }
      print2();
   }
}

이 경우, 메소드 내부에서 this를 정의해주어야 한다.

var obj = {
    print: function() {
      console.log(this); // obj 객체
      
      var _this = this;
      var print2 = function() {
        console.log(_this); // obj 객체
      }
      print2();
   }
}

2. 어떻게 호출하느냐 또한 중요하다.

var obj = {
    print: function() {
      console.log(this);
    }
}
var print = obj.print

obj.print();      // obj 객체
print();          // window 객체

obj.print()의 경우 메소드 방식으로 호출하고 있으므로 객체 자신을 가리키게 되지만,
print()의 경우 일반적인 함수 호출 방식으로 호출하고 있으므로 전역객체를 가리키게 된다.

4. 생성자 함수 내부

new 연산자로 생성자 함수를 호출할 때, 생성자 함수 내부에서 호출된 this는 생성자 함수를 통해 새로 생성되어 반환되는 객체를 가리킨다.

var foo1="foo1"
function print() {
    this.foo2 = "foo2"
    console.log(this.foo1, this.foo2)
}
print();                      // foo1 foo2
var newPrint = new print();   // undefined "foo2"

일반함수를 호출할 경우, this는 전역 객체를 가르키게 되므로 window 객체의 foo1와 foo2가 출력된다.
반면 new로 선언할 경우, this는 전역 객체가 아닌 생성된 객체를 가리키게 되므로 foo1은 undefined로 나오게 된다.

화살표 함수와 this binding

es6에서 추가된 화살표 함수 내부에서 this를 사용할 경우, this에 바인딩할 객체가 정적으로 결정되기 때문에 call, apply, bind로 this를 변경할 수 없다.

window.x = 1;
const normal = function () { return this.x; };
const arrow = () => this.x;

console.log(normal.call({ x: 10 })); // 10
console.log(arrow.call({ x: 10 }));  // 1

화살표 함수 내부의 this는 언제나 상위 스코프의 객체를 가리키는데, 이를 lexical this(문맥적 this)라고 한다.
lexical this를 제공하기 때문에 콜백 함수로 사용하기 편리하지만, 화살표 함수를 사용해서는 안 되는 경우도 존재하므로 주의해야 한다.

화살표 함수로 메소드를 선언하는 것은 위험하다

객체의 메서드를 화살표 함수로 선언할 경우, this는 해당 객체가 아닌 전역 객체를 가리키게되므로 주의해야 한다.
이 경우에는 es6의 축약 메소드 표현을 사용하는 것이 좋다.

var obj = {
    foo: "foo",
    print1: () => { console.log(this.foo) },
    print2 () { console.log(this.foo) }
}
obj.print1() // undefined
obj.print2() // foo

화살표 함수는 prototype 속성이 없다

var Foo = () => {}
console.log(Foo.prototype) // undefined
var foo = new Foo()	   // TypeError: Foo is not a constructor

addEventListener의 콜백 함수

화살표 함수는 콜백 함수로 사용하기 편리하다. 하지만 addEventListener의 콜백함수의 경우, 이벤트 리스너에 바인딩된 요소를 가리켜야 하는데 이 때 화살표 함수를 사용하면 전역 객체를 가리키게 되므로 주의해야 한다.

profile
https://jeong-min.com/ <- 블로그 이전했습니다 :)

1개의 댓글

comment-user-thumbnail
2021년 2월 22일

역시 정민님의 포스팅은 항상 도움이 되는군요!
감사합니다~

답글 달기