언어/자바스크립트

[Javascript] this 함수, 메서드 차이 (2)

youngble 2022. 6. 18. 15:57

실행컨텍스트를 활성화할 당시에 this가 지정되지 않을경우 this는 전역객체를 가리킨다고 이전에도 설명한바 있다.

이를 더글라스 크락포드(자바스크립트 언어 개발 참여자, json포멧 보급 등)는 명백한 설계상 오류 라고 지적했다. 이에 대해서 알아보고자한다.

내부함수에서의 this

var obj1 = {
  outer: function(){
      console.log(this) // (1)
      var innerFunc = function(){
      	console.log(this); // (2),(3)
      }
      innerFunc();
      
      var obj2 = {
      	innerMethod: innerFunc
      };
      obj2.innerMethod();
    }
};
obj1.outer();

다음과 같이 this를 함수내에서 console.log 출력하는 코드에 대해서 (1),(2),(3) 값을 유추해보면 왜 더글라스 크락포드명백한 설계상 오류 라고 했는지 알수있다. 답은 (1): obj1, (2): 전역객체(window), (3): obj2 이다.

(1)같은 경우 obj1.outer()로 메서드로서 함수 호출하였고 점(.)앞의 객체정보 ojb1 가 담기기 때문에 (1)은 obj1가 된다 더 정확히 말하면 {outer: f } 이다.  (2)경우는 innerFunc함수가 outer 스코프내에서 접근할수있는 지역변수이지만 함수로서의 함수호출이기 때문에 앞에 점(.)이 없으므로 this가 지정되지 않았고, 따라서 자동으로 스코프 체인상의 최상위 객체인 전역객체(window)가 바인딩된다.

(3)의 경우는 obj2.innerMethod()로 호출하여 메서드로서 호출하는것이기 때문에 점(.)앞의 객체 obj2가 바인딩된다. 따라서 (3)은 obj2가 되는거고 정확히 말하면 {innerMethod: f}가 바인딩된 것이다.

이렇게 this 바인딩에 관해서는 함수를 실행하는 당시의 주변환경(메서드 내부인지, 함수내부인지 등)은 중요하지 않고, 오직 해당 함수를 호출하는 구문앞에 점 또는 대괄호 표기가 있는지 없는지가 관건이다.

이런 자바스크립트의 this 특성이 있기때문에 더글라스 크락포드명백한 설계상 오류 라고 한것이다. 왜냐하면 호출 주체가 없을때는 자동으로 전역객체를 바인딩하지않고 호출 당시 주변환경의 this를 그대로 상속받아 사용하는게 가장 베스트이기 때문이고 그래야만 자바스크립트 설계상 스코프 체인과의 일관성이 있다. 변수를 검색하면 우선 가까운 스코프의 L.E를 찾고 없으면 상위 스코프를 탐색하듯이, this 역시 현재 실행컨텍스트에 바인딩된 대상이 없으면 직전 컨텍스트의 this를 바라보도록 말이다.

따라서 ES5까지는 이러한 설계상 오류가 있었고 해결방법으로는 변수에 this 를 담아서 쓰는 거였다.

내부함수에서 this를 우회하는 방법

var obj = {
	outer: function (){
    	console.log(this);
        var innerFunc1 = function(){
        	console.log(this);
        };
        innerFunc1();
        
        var self = this;
        var innerFunc2 = function(){
        	console.log(self);
        };
        innerFunc2();
    }
}
obj.outer();

이렇게 sefl 라는 변수에 this를 남아 innerFunc2()를 함수로서 호출하더래도 self를 쓰기때문이다.

이를  ES6에서는 함수 내부에서 this가 전역객체를 바라보는 문제를 보완하고자했다. 그 방법으로 화살표함수(arrow function)을 새로 도입한것이다. 이는 다음 글에서 설명하도록 하겠다.