티스토리 뷰

3) bind메소드로 this제어하기

this가 달라지는 경우

  • showHealth는 어떤 이유인지 바로 출력하지 못하고, 1초 뒤에 결과를 출력하는 함수입니다.
    this가 무엇을 가리킬까요

var healthObj = {

  name : "달리기",

  lastTime : "PM10:12",

  showHealth : function() {

    setTimeout(function() {

        console.log(this.name + ", 오늘은 " + this.lastTime + "에 운동을 하셨네요");     

    }, 1000)

  }

}

healthObj.showHealth();  // , 오늘은 undefined에 운동을 하셨네요

 

  • 위의 코드는 비동기 상황에서 일어나는 것으로, 이와 유사하게 비동기로 동작하는 이벤트 콜백에서 발생합니다.
    (*참고로 es6 arrow함수를 사용하는 경우 this가 가리키는 것이 또 다르니 이건 좀 당혹스러울 수 있습니다.)

 

 

  • 디버거를 이용하여 this를 한번 찍어보면 this는 Window를 가리킵니다. showHealth는 이미 반환이 됐고 그 안에 있는 콜백 함수는 윈도우를 가리킵니다.
  • 이를 해결하기 위해 bind() 메서드를 이용합니다.
  • function 바로 뒤에 .bind를 쓸 수가 있습니다. 함수 뒤에 .을 붙이면 객체로 동작합니다. 그리고 function native 객체에 들어있는 메서드들을 부를 수가 있습니다. 대표적인 게 바인드입니다. 그래서 function.bind에서 이 새로운 함수를 만들어서 그 함수가 반환이 되는 겁니다.
  • bind는 사실은 함수를 반환하는 함수입니다. 지금 return값이 없지만 return값이 원래 있는 것이며, return값이 새로운 함수로 반환되는 겁니다.
  • setTimeout()의 콜백함수 부분을 다 지우고 대신 name, lastTime을 출력하는데, this healthObj를 가리키는 함수가 자리함 이렇게 표현할 수 있습니다.

 

 

var newfunc = function(){console.log("hello");}.bind();

newfunc();   // hello

var newfunc = function(){console.log('hello');}.bind(this);

newfunc();   // hello

 

  • this를 쓰지 않는 이유는 정의한 함수가 this를 쓰는 게 없기 때문입니다그러면 newfunc이 불릴까요 안 불릴까요?
  • .bind는 this를 바인딩 하는 새로운 함수를 반환하는 함수라 했습니다. 그러니까 함수(function() {console.log('hello');}.bind(this);)가 반환이 되어서 어떤 새로운 함수가 나온 겁니다. 그걸 newfunc에 담은 거고 호출하면 비슷하게 실행이 될 것입니다.
    (그런데 es6에서는 arrow함수를 사용하는 경우에는 this가 가리키는 것이 좀 다릅니다)

 

bind method

  • bind 새로운 함수를 반환하는 함수입니다. 이부분이 좀 어색하고 혼란스러울 수 있습니다. bind동작은 특이하게도 새로운 함수를 반환한다는 점을 잘 기억해야 합니다
  • bind함수의 첫번째 인자로 this를 주어, 그 시점의 this를 기억하고 있는 새로운 (바인드된)함수가 반환되는 것입니다.

var healthObj = {

  name : "달리기",

  lastTime : "PM10:12",

  showHealth : function() {

    setTimeout(function() {

        console.log(this.name + ", 오늘은 " + this.lastTime + "에 운동을 하셨네요");     

    }.bind(this), 1000)

  }

}

healthObj.showHealth();  // 달리기님, 오늘은 PM10:12에 운동을 하셨네요

var healthObj = {

  name : "달리기",

  lastTime : "PM10:12",

  showHealth : function() {

    setTimeout(() =>{

        console.log(this.name + ", 오늘은 " + this.lastTime + "에 운동을 하셨네요");     

    }, 1000)

  }

}

healthObj.showHealth();  // 달리기님, 오늘은 PM10:12에 운동을 하셨네요

var healthObj = {

  name : "달리기",

  lastTime : "PM10:12",

  showHealth : function() {

    setTimeout((() =>{

        console.log(this.name + ", 오늘은 " + this.lastTime + "에 운동을 하셨네요");     

    }).bind(this), 1000)

  }

}

healthObj.showHealth();  // 달리기님, 오늘은 PM10:12에 운동을 하셨네요

var healthObj = {

  name : "달리기",

  lastTime : "PM10:12",

  showHealth : function() {

    setTimeout((() =>{

        console.log(this.name + ", 오늘은 " + this.lastTime + "에 운동을 하셨네요");     

    }).bind(this), 1000)

  }

}

healthObj.showHealth();    // 달리기님, 오늘은 PM10:12에 운동을 하셨네요

 

  • arrow함수는 this가 그 함수가 속해있는 것의 컨텍스트를 유지하면서 동작이 됩니다. 그러니까 bind를 할 일이 별로 없어요.
  • 오히려 this가 진짜 윈도우를 가리키게 하려면 윈도우를 바인드 시키거나 아니면 윈도우를 직접 쓰거나 해야 합니다.
  • 위 예제에서 객체리터를 표기법을 사용했으며, ES6(ES2015)부터는 객체에서 메서드를 사용할 때 'function' 키워드를 생략할 수 있습니다
    (bind에 인자를 주지 않으면 global(window) 객체가 바인딩 됩니다. 또한 strict mode에서는 undefined가 바인딩 됩니다)

 

생각해보기

  • bind 함수는 어떻게 동작할까요?
  • bind polyfill 코드를 찾아보고 어떻게 동작하는지 그 원리를 고민해보세요.
  • 자바스크립트의 특징을 좀더 이해할 수 있을 겁니다.

참고 자료 

  • MDN bind메서드 설명 링크(https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Function/bind)를 찾아서  꼭 참고하세요. 이외에도 bind에 대한 메서드 설명을 담은 내용을 찾아서 학습해보세요
  • this키워드가 아직 헷갈리시다면 this를 코드로 구현하면서 이해하거나, this에 대한 설명이 있는 자바스크립트 책을 통해서 충분히 이해하길 바랍니다

 

 

 

Comments