티스토리 뷰
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에 대한 설명이 있는 자바스크립트 책을 통해서 충분히 이해하길 바랍니다.
'부스트코스 웹 프로그래밍 > 4. 웹 앱 개발: 예약서비스 2' 카테고리의 다른 글
2. 라이브러리 활용과 클린코드 (3) (0) | 2019.07.27 |
---|---|
2. 라이브러리 활용과 클린코드 (2) (0) | 2019.07.27 |
2. 라이브러리 활용과 클린코드 (1) (0) | 2019.07.27 |
1. 객체지향 JavaScript구현 (2) (0) | 2019.07.27 |
1. 객체지향 JavaScript구현 (1) (0) | 2019.07.27 |