우선 코드를 보자.
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 |
댓글