흰 스타렉스에서 내가 내리지

[JS] class에서 this 바인딩에 대해 본문

Javascript

[JS] class에서 this 바인딩에 대해

주씨. 2022. 3. 11. 11:53
728x90
  <body>
    <button>print 'nothing' in conole</button>
  </body>

이 버튼을 누르면, 콘솔에 nothing이 찍히게 하고 싶다. 

 

만약 js파일에 코드가 이렇게 짜여져 있다면,

class Nothing {
  constructor() {
    this.nothing = document.querySelector("button");
    this.nothing.addEventListener("click", this.callPrintNothing);	// << 4번째 라인
  }

  printNothing() {
    console.log("nothing");
  }

  callPrintNothing() {
    this.printNothing();
  }
}
const nothing = new Nothing();

버튼을 아무리 눌러도 콘솔에는 메시지가 찍히지 않는다. 어째서일까?

 

 

4번째 라인에 this.callPrintNothing()에 주목하자.

addEventListener에 this.callPrintNothing 을 넘겨 주었으므로 this에 해당하는 Nothing 클래스 정보도 넘어갔을 것 같지만, 그렇지 않다. 자바스크립트에서는 클래스가 무시된 채로 '함수만' 전달이 된다. 

 

즉, 클래스 정보는 콜백으로 전달되지 않는다.

 

클래스 정보가 넘어가지 않았으므로, callPrintNothing() 함수 내부에서는 "아 this.printNothing()함수를 호출하면 되겠구나. 근데 this가 뭐지?" 가 되어버린다. 

callPrintNothing이 다른 곳으로 콜백이 전달되었을 때는, this가 존재하지 않아 printNothing()은 계속 undefined 상태이다.

 

 

따라서 클래스 정보까지 콜백으로 보내주고 싶다면, 함수를 클래스와 바인딩을 해줘야 한다. 이것을 this 바인딩이라고 한다.

 

# 해법1

// bind 함수 이용

class Nothing {
    constructor() {
      this.nothing = document.querySelector("button");
      this.callPrintNothing = this.callPrintNothing.bind(this);		// ***추가***
      this.nothing.addEventListener("click", this.callPrintNothing);
    }

    printNothing() {
      console.log("nothing");
    }

    callPrintNothing() {
      this.printNothing();
    }
  }
  const nothing = new Nothing();

직접적으로 bind() 함수를 이용하여 클래스와 bind 해준다.

 

# 해법2

class Nothing {
  constructor() {
    this.nothing = document.querySelector("button");
    this.nothing.addEventListener("click", () => this.callPrintNothing());	// ***수정***
  }

  printNothing() {
    console.log("nothing");
  }

  callPrintNothing() {
    this.printNothing();
  }
}
const nothing = new Nothing();

콜백으로 전달되는 함수를, this.callPringNothing() 함수 자체를 줄게 아니라, arrow function으로 한 번 더 감싸준다.

arrow function은 this가 유지되기 때문이다.

 

# 해법3

class Nothing {
  constructor() {
    this.nothing = document.querySelector("button");
    this.nothing.addEventListener("click", this.callPrintNothing);
  }

  printNothing() {
    console.log("nothing");
  }

  callPrintNothing = () => {	// ***수정***
    this.printNothing();
  };
}
const nothing = new Nothing();

클래스 안에 있는 어떤 함수를 다른 콜백으로 전달할 때는, 그 함수를 변수화 한다.

즉, callPrintNothing 이라는 변수를 만들고, 그 변수가 우리가 원하는 arrow function 로직을 가리키도록 한다.

 

 

 

 

 

 

결론:

어떤 클래스 안에 있는 함수를 다른 콜백으로 전달할 때는 그 함수가 위치한 클래스의 정보가 사라진다.

따라서 클래스와 함수를 묶는 binding과정이 필요하다.