본문 바로가기
tech documents/javascript

Class의 this binding

by kimtahen 2020. 7. 3.
반응형

우선 코드를 보자.

var word = "good morning";
class helloWorld {
    word = "good evening";
    greetings(){
        console.log(this.word);
    };
}

이렇게 예시코드를 작성한 뒤, helloWorld 클래스를 생성자로 하는 새로운 객체를 생성해보자.

let obj = new helloWorld();

여기서 obj.greetings() 이렇게 메서드를 실행하면, this는 메서드를 호출한 객체인 obj에 binding 되기 때문에 "good evening" 이 출력된다. 

chrome 의 developer tool - console 에서 실행한 화면이다. 

 

그렇다면 이제는 새로운 객체에 greetings 메서드를 할당하면 어떻게 될까? 아래와 같은 방식으로 말이다.

let objA = obj.greetings;

이렇게 objA를 생성하고 objA(); 이렇게 실행해보자. 그러면 아래와 같은 오류가 발생한다. 

this가 바인딩 되지 않았기 때문이다. (왜 자동으로 전역 객체를 가리키지 않는지는 아직은 잘 이해가 되지 않는다. 조금더 고민해 보아야 할 문제이다.)

 

이번에는 아래와 같이 코드를 작성하고 실행해보자.

let objB = obj.greetings.bind(this);

이 경우에는  good morning 이 출력된다. obj의 greetings 메서드에 정적으로 전역객체를 binding 하여 objB를 생성하였기 때문이다. 

 

그러니 결론적으로 good evening 이라는 값을 정상적으로 출력하기 위해서는

let objC = obj.greetings.bind(obj);

이런 식으로 obj 자체를 binding 해주어야 한다.

 


1.

결론적으로 문제는 클래스의 메서드를 재할당 할 때 발생할 것이다. 따라서, 때로는 클래스 메서드를 정의할 때 정적으로 바인딩 해주는 작업이 중요할 것이다. 따라서 아래와 같이 코드를 작성해보자. constructor에서 정적으로 클래스를 바인딩 해주는 방식이다.

var word = "good morning";
class helloWorld {
    constructor(){
        this.greetings = this.greetings.bind(this)
    }
    word = "good evening";
    greetings(){
        console.log(this.word);
    };
}

객체를 생성할 시, 객체의 greetings 메서드에 생성되는 객체 자체를 정적으로 binding 시켜 버린다. 이제 문제가 발생했었던 코드를 다시 작성해보면 

let obj = new helloWorld();
let objA = obj.greetings;
objA();

정적으로 obj가 바인딩 되어 있기 때문에, greetings 함수를 재할당 해도 오류가 발생하지 않는 것을 확인할 수 있다.

 

2. 

이런 과정 없이, 간단하게 사용할 수 있는 방법이 한가지 있다. 바로 화살표함수를 사용하는 것이다. 

일반 함수의 경우에는(1번에서 사용한 방식) 함수 호출 방식에 의해 this binding이 동적으로 결정 된다. 그렇기 때문에 그 메서드를 재할당 할 때 문제가 발생하는 것이다. 하지만 화살표 함수의 경우 this binding이 정적으로 결정된다. 이 경우에는, 화살표 함수의 this는 언제나 상위 스코프의 this를 가리킨다. 항상 Lexical scope 방식을 따라서 정적으로 결정된다는 의미이다. 

var word = "good morning";
class helloWorld {
    word = "good evening";
    greetings=()=>{
        console.log(this.word);
    };
}

이 코드에서 greetings의 상위 스코프는 class helloWorld 가 해당 된다. 따라서 greetings 의 this는,  class hellWorld로 생성되는 객체의 this 를 바인딩하게 된다.

let obj = new helloWorld();
let objA = obj.greetings;
objA();

정적으로 바인딩 된 것을 확인할 수 있다.

 

3. 

리액트에서는 this를 바인딩 하는 것이 꽤나 중요한 문제이다. 컴포넌트를 class로 정의하는데, class 매서드를 돔 요소와 연결하는 과정에서 this의 의미가 모호해질 수 있기 때문이다. 따라서 class 컴포넌트를 사용할 때는 1, 2 번의 방식을 따라 정의해 주는 것이 중요할 것이다. 또한, 이는 1, 2번 두 방식 중 하나를 무조건 택해서 정의해야 하는 이유 이기도 하다.

반응형

'tech documents > javascript' 카테고리의 다른 글

Immutable.js (Writing)  (0) 2020.07.05
전역객체의 property  (0) 2020.07.04
[Javascript] Sync, Async 그리고 event loop  (0) 2020.04.10
[Webpack] file-loader  (0) 2020.03.11

댓글