[자바스크립트 bind(this)]
순수 자바스크립트 코드에서 이벤트 핸들러 함수의 this는 무엇을 가르킬까?
<script>
window.onload = function () {
document.getElementById("test").onclick = function(e){
console.log(this);
}
};
</script>
<div id="test"></div>
이벤트 핸들러가 적용된 Element객체를 가르킨다.
만약 위와 동일한 코드에서 이벤트 핸들러 함수에 bind(this)를 한다면 어떻게될까?
<script>
window.onload = function () {
document.getElementById("test").onclick = function(e){
console.log(this);
}.bind(this);
};
</script>
<div id="test"></div>
Global 객체인 Window객체를 가르키게된다.
HTML 태그의 이벤트 속성으로 함수를 호출해본다.
<div id="test" onclick='(function () {
console.log(this)
})()'>테스트다</div>
bind를 하지 않았을 때에는 Global객체인 Window를 가르킨다..
<div id="test" onclick='(function () {
console.log(this)
}.bind(this))()'>테스트다</div>
bind(this) 처리 한 뒤, 이윽고 결실을 맺었다...!
[bind() 함수를 통해 객체에 값 전달]
다음은 bind함수를 통해 값을 전달해본다.
<script>
window.onload = function () {
document.getElementById("test").onclick ={function(id, e){
/* bind함수에 두번째인자값은 이벤트함수의 콜백함수 매개변수의 첫번째 인자값으로 매핑가능
만약 bind함수 인자값이 두개라면 콜백함수 인자로 앞에서부터 동일하게 순차적으로 나열한다. */
console.log(this); // <div id="test"></div>
console.log(id) // => 15를 출력한다.
}.bind('15')}
};
</script>
<div id="test"></div>
<script>
window.onload = function () {
document.getElementById("test").onclick = function(id,name, e){
/* bind함수에 두번째인자값은 이벤트함수의 콜백함수 매개변수의 첫번째 인자값으로 매핑가능
만약 bind함수 인자값이 두개라면 콜백함수 인자로 앞에서부터 동일하게 순차적으로 나열한다. */
console.log(this); // Window 객체
console.log(id) // => 15를 출력한다.
console.log(name) // => 고슬링을 출력한다.
}.bind(this, '15','고슬링')
};
</script>
<div id="test"></div>
위에서 다루었던것과 같이 순수 자바스크립트 코드 상에서 bind(this)를 선언하면, 이벤트핸들러 함수 내부의 this는 Global 객체인 Window를 가리키게된다.
onclick 이벤트 핸들러 함수는 id가 test인 div객체에 적용되었으므로, 해당 객체가 가르키는 this는 Window 객체가 된다?
(잘 모르겠음... 아래 링크 참조..)
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
바인딩한 함수를 호출하면 일반적으로 래핑된 함수가 호출
어쨋든, bind()함수 첫번째 매개변수가 this이고 두번째 매개변수부터 순차적으로 값을 부여했을 경우 함수 선언부에서 해당 값을 첫번째 매개변수부터 순차적으로 받을 수 있게 됩니다.
만약 첫번째 매개변수로 this를 받지 않는다 하더라도, 선언부 에서는 동일하게 첫번째 매개변수부터 순차적으로 값을 받습니다.
이때, 함수 선언부의 마지막 매개변수는 event객체를 받습니다.
[React 에서의 Bind(this)]
class App extends Component {
constructor(props){
super(props);
this.state = {
mode:'read'
}
}
render() {
return (
<Subject onChangePage={function() {
this.setState({mode:"welcome"});}.bind(this)}/>
)
}
위와같은 React코드가 있다고 할때
컴포넌트의 render() 함수가 실행되면 DOM이 그려지고
이때의 this는 Component 내부에서 선언한 method의 객체를 가리키는것이 맞지만,
event Handler함수가 호출될때의 this는 컴포넌트 내부에서 선언한 method 객체를 가리키는것이 아닌 (예를들면 this = App) 전역객체인 Window객체를 가리키게 됩니다.
따라서 eventHandler함수인 onChangePage 부에서 App 컴포넌트 객체인 this를 사용하기 위해서는 함수 가 닫히는 블럭에 .bind(this) 함수를 사용하여 Global객체 즉 Window객체가 아닌 App 객체를 가리키도록 명시적으로 선언해줍니다.
class App extends Component {
constructor(props){
super(props);
this.state = {
mode:'read'
}
}
render() {
return (
<Subject onChangePage={() => {
this.setState({mode:"welcome"});}}/>
)
}
만약 EventHandler함수 내부에서 화살표 함수로 사용하게 된다면 bind(this)처리 하지 않아도 this는 Global객체를 가리키지 않고 현재 이벤트가 발생된 객체를 가리키게 됩니다.
(이유는 더 알아보겠습니다.)
[setInterval 함수의 bind(this) 처리]
아래 코드와 같이 setInterval함수에서도 이벤트 핸들러 함수가 아닌데 bind(this) 처리를 해줍니다.
class ProgressEx extends Component {
constructor(props) {
super(props);
this.state={progress:0}
}
progress = () => {
if(this.state.progress !== 100 ) {
setInterval(function() {
console.log(this)
if(this.state.progress == 100) {
return;
}
this.setState({progress:this.state.progress+1})
}.bind(this), 100);
// let id = setInterval(()=>{
// if(this.state.progress == 100) {
// // clearInterval(id);
// return;
// }
// this.setState({progress:this.state.progress+1})
// },100)
}
}
componentDidMount () {
this.progress();
}
render() {
return (
<Progress color="info" value={this.state.progress}>
{this.state.progress}
</Progress>
)
}
}
이벤트함수와 동일한 맥락으로 봤을때 setInterval함수는 Global 소속이기때문에 Window객체를 가리키게 됩니다.
그래서 setInterval함수 내부에서 내가 가리키고 싶은 this 즉 ProgressEx객체를 가리키기 위해서는
.bind(this)를 통해 명시적으로 ProgressEx객체를 가리켜야 합니다.
이 역시 화살표 함수를 사용하면 따로 bind(this) 처리를 하지 않아도 됩니다.
[React 에서의 bind() 함수를 통한 객체에 값 전달]
<a href="#" onClick={function(id, e){
console.log(id); // '아이디' 출력
}.bind(this, "아이디"}>
형태만 봐도 일반 HTML태그가 아닌 React태그인것을 확인할 수 있다
React에서는 이벤트 속성을 onclick이 아닌 onClick과 같이 공백 구분 글자를 대문자로 처리하고
"따옴표" 가 아닌 {중괄호} 처리로 이벤트 핸들러 함수를 감싼다.
bind함수의 값 전달은 위에서 설명했던 순수 자바스크립트 설명에서와 같이 똑같이 적용된다.