Javascript/ES5 & ES6

This, 리액트에서의 bind()

덕구공 2021. 7. 15. 15:43

This

  • this는 자신이 속한 객체 또는 자신이 생성할 인스턴스를 가리키는 자기 참조 변수이다.
  • 즉, this는 함수가 호출되는 방식에 따라 동적으로 결정된다!

자바스크립트에서 this는 크게 4가지로 사용될 수 있다.

  • 일반 함수 내부 (전역 객체 바인딩)
  • 메서드 내부 (메서드를 호출한 객체 바인딩)
  • 생성자 함수 (생성자 함수가 생성할 인스턴스 바인딩)
  • apply/call/bind 호출 (메서드에 첫 번째 인수로 전달하는 객체 바인딩)

일반 함수 내부 this

  • 일반 함수 내부에서 호출한 this는 전역 객체에 바인딩된다.
var a = 4

function duck(){
    console.log(this.a);
}

duck(); //4

 


메서드 내부 this

  • 메서드 안에서 this를 호출하면 this는 메서드를 호출한 객체에 바인딩된다.
  • 메서드란 객체에 종속된 함수이다.
const duck = {
    a: 4,
    b: 5,
    sum: function(){
        console.log(this.a + this. b)
    }
};

duck.sum(); //9
  • 클래스 형식에서도 같은 방식으로 동작한다.
class Duck{
    constructor(){
        this.a = 4;
        this.b = 5;
    }
    render(){
        return(this.a + this.b);
    }
}

var duck = new Duck();
console.log(duck.render());  //9

생성자 함수 this

  • 생성자 함수로 this를 호출 할 때, 생성자 함수가 생성할 객체에 바인딩된다.
function Duck(c, d){
    this.a = c;
    this.b = d;
    this.sum = function(){
        console.log(this.a + this.b);
    }
}

const duck = new Duck(4, 5);

duck.sum //9

arrow function this

  • 일반 함수에서는 this가 어떻게 호출 되었는지에 따라 다르게 바인딩할 객체가 동적으로 결정되는 반면에, arrow function의 this는 함수를 선언할 때 바인딩 할 객체가 정적으로 결정된다!
  • arrow function의 this는 언제나 상위 스코프의 this를 가리킨다!
    • 이를 Lexical this라고 부른다!

 

  • 아래와 같은 경우 메서드를 arrow function으로 선언한 후 this를 선언하면 duck 객체의 상위 스코프인 window 객체를 가르키고 "lee"가 출력된다!
var name = "lee";
var duck = {
    name: "duck",
    getName: () => console.log(this.name)
};
duck.getName();

apply/call/bind this

  • apply/call/bind는 함수에 객체를 this로 바인딩하는 역할을 한다.

apply

  • apply 함수의 첫 번째 인자로 전달하는 객체에 this를 바인딩하고 함수를 실행한다. 그리고 두번째 인자에 바인딩할 함수의 인자를 배열의 형태로 전달한다.
function duck(a, b){
    console.log(this.name);
    console.log(a + b);
}
duck();
// undefined
// NaN

let person = {
    name: 'duck'
}

duck.apply(person,[1,2]);
// duck
// 3

call

  • apply 함수의 첫 번째 인자로 전달하는 객체에 this를 바인딩하고 함수를 실행한다. 그리고 두번째 인자부터 바인딩할 함수의 인자를 차례대로 전달한다.
function duck(a, b){
    console.log(this.name);
    console.log(a + b);
}
duck();
// undefined
// NaN
let person = {
    name: 'duck'
}

duck.call(person, 1, 2);
// duck
// 3

bind (중요!)

  • bind의 첫번째 인자로 넘어간 객체에 바인딩하는 것은 apply와 call과 같지만, bind는 함수를 실행하지 않고 새로운 함수를 반환한다. 
  • 새로운 함수를 반환하기 때문에 실행을 시켜주지 않으면 따로 실행이 되지 않는다.
function duck(a, b){
    console.log(this.name);
    console.log(a + b);
}
duck();

let person = {
    name: 'duck'
}

const newduck= duck.bind(person, 1, 2);

newduck();
var obj = {name : 'duck'};

function bindTest(){
    console.log(this.name);
}
bindTest();
// undefined

var bindTest2 = bindTest.bind(obj);
bindTest2()
// duck

리액트에서 bind() 사용

  • 리액트사용시 어떤 이벤트가 발생한 리액트 요소에서 state 값을 변경할 때 사용하기도 한다.
  • 어떤 이벤트가 발생한 요소에서의 this는 아무것도 가리키지 않기 때문에 이벤트가 발생했을 때 실행되는 함수에 .this()를 붙여준다.

 

  • 아래처럼 코드를 작성하면 오류가 발생한다.
  • 이벤트 안에서의 this는 컴포넌트 자신을 가리키지 않고 아무것도 가리지 않아서 this를 찾을 수 없기 때문이다.
import React from 'react';

class App extends React.Component{
  constructor(props){
    super(props);
    this.state = {
      duck: 1
    }
  }
  render(){
    return(
      <div onClick={function(){
        this.setState({duck: 2})
      }} style ={{background: 'blue'}}>
        <h1>{this.state.duck}
        </h1>
      </div>
    );
  }
}

export default App;
  • 아래처럼 이벤트가 발생했을 때 실행되는 함수에 .bind(this)를 붙여서 this가 컴포넌트를 가리키게 하면 오류가 발생하지 않는다!
import React from 'react';

class App extends React.Component{
  constructor(props){
    super(props);
    this.state = {
      duck: 1
    }
  }
  render(){
    return(
      <div onClick={function(){
        this.setState({duck: 2})
      }.bind(this)} style ={{background: 'blue'}}>
        <h1>{this.state.duck}
        </h1>
      </div>
    );
  }
}

export default App;