자바스크립트 this

업데이트:

1. 자바스크립트에서의 this

자바스크립트를 공부하면서 this에 대해 알 듯 모를 듯 해서 이번기회에 예제를 이용해 다시 정리해봅니다.
언어마다 어느정도 차이가 있겠지만 대표적으로 자주 사용하는 JAVA에서의 this 키워드는 자기자신을 가리키는 키워드입니다. 즉 this 키워드를 통해 클래스 메서드 및 생성자에서 자신의 데이터를 업데이트하거나 조작할 수 있습니다.
하지만 자바스크립트의 this는 조금 다릅니다. 간단히 설명하자면 자바스크립트에서의 this는 호출한 곳을 가리키게 됩니다.
React로 만든 구구단 예제를 통해 this에 대해 알아보겠습니다.

2. React 구구단 예제를 통해 알아보는 this

create-react-app을 사용하지 않고 html파일에 그대로 복사붙여넣기하면 됩니다.

2.1 구구단예제 html 소스

<!doctype html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <meta name="viewport"
        content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <script src="https://unpkg.com/react@16/umd/react.development.js"></script>
  <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
  <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
  <title>React Study</title>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
  class GuGuDan extends React.Component {
    constructor( props ) {
      super(props);
      this.state = {
        num1  : this.random(2, 9),
        num2  : this.random(1, 9),
        value : '',
        result: ''
      };
      // this.onSubmit = this.onSubmit.bind(this);
      console.log(this);
    }

    random( min, max ) {
      return Math.floor(( Math.random() * ( max - min + 1 ) ) + min);
    };

    resetRandom() {
      this.setState({
        num1: this.random(2, 9),
        num2: this.random(1, 9),
      });
    };

    resetValue() {
      this.setState({
        value: ''
      });
    }

    onSubmit( e ) {
      e.preventDefault();
      if (( this.state.num1 * this.state.num2 ) === parseInt(this.state.value)) {
        this.setState(( prevState ) => {
          return {
            result: `${prevState.num1} x ${prevState.num2} = ${prevState.value} | 정답 ✅`
          };
        });
        this.resetRandom();
        this.resetValue();
      } else {
        this.setState(( prevState ) => {
          return {
            result: `${prevState.num1} x ${prevState.num2} = ${prevState.value} | 땡 ❌`
          };
        });
        this.resetValue();
      }
    };

    onChange = ( e ) => {
      this.setState({
        value: e.target.value,
      });
    };

    render() {
      return (
        <React.Fragment>
          <h1>{this.state.num1} X {this.state.num2} ??</h1>
          <form onSubmit={this.onSubmit}>
            <input type="number" value={this.state.value} onChange={this.onChange}/>
            <button>입력</button>
          </form>
          <div>{this.state.result}</div>
        </React.Fragment>
      );
    }
  }
</script>
<script type="text/babel">
  ReactDOM.render(
    <React.Fragment>
      <GuGuDan/>
    </React.Fragment>, document.querySelector('#root')
  );
</script>
</body>
</html>

우선 위의 코드를 복사해서 .html 파일안에 붙여넣어서 실행하세요!

2.2 구구단예제 실행 결과

profile

실행하면 위와 같은 화면이 뜨고 숫자를 입력할 수 있는 input창 하나가 존재합니다. 이제 숫자를 입력하고 입력버튼을 눌러보겠습니다.
아무런 반응이 없죠?? 저희는 분명


<form onSubmit={this.onSubmit}>
  <input type="number" value={this.state.value} onChange={this.onChange}/>
  <button>입력</button>
</form>
onSubmit(e)
{
  console.log(this); // undefined 
  e.preventDefault();
  if (( this.state.num1 * this.state.num2 ) === parseInt(this.state.value)) {
    this.setState(( prevState ) => {
      return {
        result: `${prevState.num1} x ${prevState.num2} = ${prevState.value} | 정답 ✅`
      };
    });
    this.resetRandom();
    this.resetValue();
  } else {
    this.setState(( prevState ) => {
      return {
        result: `${prevState.num1} x ${prevState.num2} = ${prevState.value} | 땡 ❌`
      };
    });
    this.resetValue();
  }
}
;

입력버튼을 누르면 this.onSubmit 함수가 동작해야 하는데 동작이 되질 않습니다.
이러한 오류가 생기는 이유는 this 키워드는 호출한 곳을 가리키게 되서 그렇습니다.
onSubmit(e) {} 함수에 console.log(this)를 찍어보면 undefined가 찍히는 것을 볼 수 있습니다.
우리가 this키워드를 사용해서 GuGuDan class의 onSubmit 함수를 가리키게 하려면 bind를 해줘야합니다. bind를 해주는 방법은 클래스 생성자 constructor() { … } 안에 this.onSubmit = this.onSubmit.bind(this); 사용해서 GuGuDan class객체가 생성될 때 onSubmit을 bind(묶다) 해주면 앞으로 어디서든 this 키워드를 사용해서 onSubmit()함수를 불러올 수 있습니다.

2.3 조금 더 쉽게 이해하는 방법

저도 처음 자바스크립트를 접하고 this에 대해 많이 헷갈렸습니다. (물론 지금도..😂)
위와 같은 설명이 잘 이해가 가지 않으신 분은 조금 더 이해하기 좋은 방법이라고 생각합니다.
제가 조금 더 이해하는데 도움되었던 확인 방법은 class를 생성했을 때 constructor() {} 생성자 함수 내에서 console.log(this)를 찍어보는 것 이었습니다.

우선 구구단 클래스에 생성자 함수에서 this.onSubmit을 바인딩 해준 것을 다시 주석처리하고 console.log(this)를 해보도록 하겠습니다.

class GuGuDan extends React.Component {
  constructor( props ) {
    super(props);
    this.state = {
      num1  : this.random(2, 9),
      num2  : this.random(1, 9),
      value : '',
      result: ''
    };
    //this.onSubmit = this.onSubmit.bind(this);
    console.log(this);
  }

...
...

2.3.1 onSubmit 바인딩 안해줬을 때

profile
바인딩 안해줬을 때 GuGuDan 클래스의 this는 onSubmit 함수를 포함하고 있지 않음

2.3.2 onSubmit 바인딩 해줬을 때

profile
바인딩 해줬을 때 GuGuDan 클래스의 this는 onSubmit 함수를 포함하고 있음

bind를 해줬을 때와 안해줬을 때 클래스에서의 this가 가지고 있는 객체들

bind를 안해줬을 때 this 키워드가 onSubmit 함수를 찾지못한 이유는


<form onSubmit={this.onSubmit}>
  <input type="number" value={this.state.value} onChange={this.onChange}/>
  <button>입력</button>
</form>

와 같이 form에서 this키워드가 불러졌고 this키워드는 앞서 설명한 것과 같이 호출한 곳을 가리킵니다.

2.4 화살표 함수를 사용하는 이유!!

화살표 함수는 ES6 문법으로 const name = () => {} 와 같이 사용합니다.
예제와 같이 onSubmit(e){} 와 같이 함수를 선언하게 되면 bind 작업이 필요하지만 화살표 함수를 사용하게 되면 클래스 내에 자동으로 bind 해줍니다. 귀찮게 일일이 bind해줄 필요가 없습니다.

onSubmit (e) { }         // bind 필요
onSubmit = ( e ) => { }  // 자동으로 class에 bind 해줌

직접 확인해보시려면 위의 html코드 예제에서 생성자 함수인 constructor안에 있는 this.onSubmit = this.onSub... 를 삭제하시면 됩니다!

2.5 random, resetRandom, resetValue 함수 bind가 필요 없는 이유

다시 한 번 말하자면 this 키워드는 호출된 곳을 가리킵니다. random,resetRandom,resetValue 함수는 같은 클래스 내에서 호출이 이루어지므로 각각의 함수에 console.log(this)를 해보면 GuGuDan 클래스를 가리키는 것을 확인할 수 있습니다.

random(min, max)
{
  console.log('random');
  console.log(this);
  return Math.floor(( Math.random() * ( max - min + 1 ) ) + min);
}

resetRandom()
{
  console.log('resetRandom');
  console.log(this);
  this.setState({
    num1: this.random(2, 9),
    num2: this.random(1, 9),
  });
}

resetValue()
{
  console.log('resetValue');
  console.log(this);
  this.setState({
    value: ''
  });
}

profile


만약 아래와 같이 숫자를 바꿀 수 있는 버튼을 만들었고

<React.Fragment>
  <h1>{this.state.num1} X {this.state.num2} ??</h1>
  <form onSubmit={this.onSubmit}>
    <input type="number" value={this.state.value} onChange={this.onChange}/>
    <button>입력</button>
  </form>
  <button type="submit" onClick={this.resetRandom}>숫자 바꾸기</button>
  <div>{this.state.result}</div>
</React.Fragment>

숫자 바꾸기 button을 클릭했을 때 resetRandom 함수를 호출하려면 resetRandom 을 직접 bind 해주거나, resetRandom = () => {} 화살표 함수로 바꿔주기만 하면 됩니다.


참고
MDN

댓글남기기