본문 바로가기

Javascript

JavaScript - this와 호출, bind

자바스크립트에서의 함수의 this 키워드는 다른 언어들과 비교하여 조금 다르게 동작한다. 또한 strict mode 와 non-strict mode 사이에서도 조금 다르다.

 

호출 장소

대부분의 경우에 this의 값은 함수를 호출하는 방법에 의해 결정된다. 자바스크립트에서는 선언 때 결정되는 것이 있고, 호출할 때 결정되는 것이 있는데, this의 핵심은 호출하는 방법에 따라 결정된다는 것이 핵심이다. ES5는 함수의 this 값이 함수가 어떻게 호출되었는지 개의치 않고 설정할 수 있는 방법이 있는데, 바로 bind 메서드의 사용이다.

 

먼저 아래와 같은 객체를 만들어 실행해보자.

 

var me = {
    name: 'beom seok',
    sayMyName: function() {
        console.log(this);
    }
};

me.sayMyName();

 

결과

 

PS C:\Users\bumsu\nodejs-projects\노드js교과서> node main 
{ name: 'beom seok', sayMyName: [Function: sayMyName] }

 

객체 안의 this가 가리키는 건 위 상황에선 객체 자체이다. 그렇다면 다른 방법으로 호출해보자.

 

var me = {
    name: 'beom seok',
    sayMyName: function() {
        console.log(this);
    }
};

me.sayMyName();

var howAboutThis = me.sayMyName;

howAboutThis();

 

결과

 

PS C:\Users\bumsu\nodejs-projects\노드js교과서> node main
{ name: 'beom seok', sayMyName: [Function: sayMyName] }
<ref *1> Object [global] {
  global: [Circular *1],
  clearInterval: [Function: clearInterval],
  clearTimeout: [Function: clearTimeout],
  setInterval: [Function: setInterval],
  setTimeout: [Function: setTimeout] {
    [Symbol(nodejs.util.promisify.custom)]: [Function (anonymous)]
  },
  queueMicrotask: [Function: queueMicrotask],
  clearImmediate: [Function: clearImmediate],
  setImmediate: [Function: setImmediate] {
    [Symbol(nodejs.util.promisify.custom)]: [Function (anonymous)]
  }
}

 

결과를 보면 me.sayMyName은 me 객체를 호출하는 것을 볼 수 있다. 그러나 howAboutThis에서는 this가 상위 객체인 global을 가리키게 된다 (위 코드는 노드js에서 실행되었다). 그렇다면 호출 방식에 따라서 이 this가 결정된다는 것은 무슨 말일까?

 

위의 코드를 보면 sayMyName 함수는 어디서 호출되었냐 하면 me라는 객체에서 호출되었다. 즉 호출되는 곳이 객체 내부이므로 객체를 this로 지정하게 된다. 그러나 howAboutThis 함수는 전역에서 호출이 전역에서 되었다. 즉 코드를 실행하는 global 객체 자체를 호출한 셈이 된다.

 

addEventListener

addEventListener 함수에서는 또 다르게 작동된다. 아래와 같은 index.html 파일과 main.js 파일을 만들고 버튼을 호출해보자.

 

<button id="btn">Hello!</button>
<script src="./main.js"></script>

 

var me = {
    name: 'beom seok',
    sayMyName: function() {
        console.log(this);
    }
};

me.sayMyName();

var btn = document.getElementById('btn');
btn.addEventListener('click', me.sayMyName);

 

실행하고 버튼을 눌러보면 아래와 같은 결과가 나온다.

이상하다. 분명 me.sayMyName을 호출했으므로 me 객체가 콘솔에 찍혀야하는 것이 아닌가? 이는 왜 그렇냐 하면, 이 함수를 호출한 대상은 버튼이기 때문이다. 즉, me에서 호출을 한 것이 아니라, 버튼의 addEventListener메서드로 해당 함수를 호출했기 때문에, 호출한 대상인 버튼을 this가 가리키게 되는 것이다. 함수는 객체에서 꺼내지기만 할 뿐, 실행하고 호출한 대상은 버튼이기 때문에 함수의 this는 자신을 호출한 버튼을 가리키게 된다.

 

bind

이번엔 bind를 써보자. 아래와 같이 main.js 파일을 고쳐주고 버튼을 눌러보자.

 

var me = {
    name: 'beom seok',
    sayMyName: function() {
        console.log(this);
    }
};

me.sayMyName();

var bindedSayMyName = me.sayMyName.bind(me);

var btn = document.getElementById('btn');
btn.addEventListener('click', bindedSayMyName);

 

 

위와 같이 의도했던 대로 me 객체가 잘 찍히는 것을 볼 수 있다.

 

bind는 한 가지 예외의 경우이다. bind를 사용하는 경우를 제외하고는 모두 this는 호출한 대상을 가리키게 된다. 그러나 bind로 묶어주게 되면, 묶어준 해당 객체를 this로 가리키게 된다. 예외적인 경우이며, 아주 유용하게 쓰일 수 있다.

 

출처

https://www.youtube.com/watch?v=PAr92molMHU

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/this