들어가며.

1. 상황에 따라 달라지는 this

<aside> 💡 - 실행 컨텍스트실행할 코드에 제공할 환경 정보들을 모아놓은 객체이다.

</aside>

1-1. this는 실행 컨텍스트가 생성될 때 결정된다.

1-2. 메서드로서 호출할 때 그 메서드 내부에서의 this

  1. 함수 vs 메서드

    함수와 메서드, 상당히 비슷해 보이지만 엄연한 차이가 존재한다. 기준은 독립성으로 함수는 그 자체로 독립적인 기능을 수행한다.

    함수명();
    

    그러나 메서드는 자신을 호출한 대상 객체에 대한 동작을 수행한다.

    객체.메서드명();
    
  2. this의 할당

    // CASE1 : 함수
    // 호출 주체를 명시할 수 없기 때문에 this는 전역 객체를 의미해요.
    var func = function (x) {
    	console.log(this, x);
    };
    func(1); // Window { ... } 1
    
    // CASE2 : 메서드
    // 호출 주체를 명시할 수 있기 때문에 this는 해당 객체(obj)를 의미해요.
    // obj는 곧 { method: f }를 의미하죠?
    var obj = {
    	method: func,
    };
    obj.method(2); // { method: f } 2
    
  3. 함수로서의 호출과 메서드로서의 호출 구준 기분 : .[]

    점으로 호출하든 대괄호로 호출하든 결과는 같다.

    var obj = {
    	method: function (x) { console.log(this, x) }
    };
    obj.method(1); // { method: f } 1
    obj['method'](2); // { method: f } 2
    
  4. 메서드 내부에서의 this

    위의 내용에서 보았듯, this에는 호출을 누가 했는지에 대한 정보가 담긴다.

    var obj = {
    	methodA: function () { console.log(this) },
    	inner: {
    		methodB: function() { console.log(this) },
    	}
    };
    
    obj.methodA();             // this === obj
    obj['methodA']();          // this === obj
    
    obj.inner.methodB();       // this === obj.inner
    obj.inner['methodB']();    // this === obj.inner
    obj['inner'].methodB();    // this === obj.inner
    obj['inner']['methodB'](); // this === obj.inner
    
  5. 함수로서 호출할 때 그 함수 내부에서의 this

    1. 함수 내부에서의 this

      1. 어떤 함수를 함수로서 호출할 경우, this는 지정되지 않는다. (호출 주체를 알 수 없기에)
      2. 실행컨텍스트를 활성화할 당시 this가 지정되지 않은 경우, this는 전역 객체를 의미한다.
      3. 따라서, 함수로서 독립적으로 호출할 때는 this는 항상 전역객체를 가리킨다는 것을 주의하자.
    2. 메서드의 내부함수에서의 this

      1. 예외는 없다. 메서드의 내부라고 해도, 함수로서 호출한다면 this는 전역 객체를 의미한다.

        var obj1 = {
        	outer: function() {
        		console.log(this); // obj1
        		var innerFunc = function() {
        			console.log(this); // (2), (3)
        		}
        		innerFunc(); // 여기서 출력한 this (2) -> window
        
        		var obj2 = {
        			innerMethod: innerFunc
        		};
        		obj2.innerMethod(); // 여기서 출력한 this (3) -> obj2
        	}
        };
        obj1.outer();
        

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

        </aside>

    3. 메서드의 내부 함수에서의 this 우회

      this는 상당히 애매모호하고 받아들이기가 어려운 점이 많다. 그렇기에 this를 우회할 수 있는 방법을 찾아볼 수 있다.

      1. 변수를 활용하는 방법

        내부 스코프에 이미 존재하는 this를 별도의 변수 (ex: self) 에 할당하는 방법.

        var obj1 = {
        	outer: function() {
        		console.log(this); // (1) outer
        
        		// AS-IS
        		var innerFunc1 = function() {
        			console.log(this); // (2) 전역객체
        		}
        		innerFunc1();
        
        		// TO-BE
        		var self = this;
        		var innerFunc2 = function() {
        			console.log(self); // (3) outer
        		};
        		innerFunc2();
        	}
        };
        
        // 메서드 호출 부분
        obj1.outer();
        
      2. 화살표 함수 (=this를 바인딩하지 않는 함수)

        1. ES6에서 처음 도입된 화살표 함수는, 실행 컨텍스트를 생성할 때 this 바인딩 과정 자체가 없다. 따라서 this는 이전의 값 - 상위 값 - 이 유지된다. / ES6에서는 함수 내부에서 this가 전역 객체를 바라보는 문제 때문에 화살표 함수를 도입했다.)

          일반 함수와 화살표 함수의 가장 큰 차이점은 무엇일까?

          → 바로 this binding 여부가 가장 적절한 답변.

          var obj = {
          	outer: function() {
          		console.log(this); // (1) obj
          		var innerFunc = () => {
          			console.log(this); // (2) obj
          		};
          		innerFunc();
          	}
          }
          
          obj.outer();
          
  6. 콜백 함수 호출 시 그 함수 내부에서의 this

    콜백함수?

    “어떠한 함수, 메서드의 인자(매개변수)로 넘겨주는 함수”

    // 별도 지정 없음 : 전역객체
    setTimeout(function () { console.log(this) }, 300);
    
    // 별도 지정 없음 : 전역객체
    [1, 2, 3, 4, 5].forEach(function(x) {
    	console.log(this, x);
    });
    
    // addListener 안에서의 this는 항상 호출한 주체의 element를 return하도록 설계되었음
    // 따라서 this는 button을 의미함
    document.body.innerHTML += '<button id="a">클릭</button>';
    document.body.querySelector('#a').addEventListener('click', function(e) {
    	console.log(this, e);
    });
    
    1. setTimeout 함수, forEach 메서드는 콜백 함수를 호출할 때 대상이 될 this를 지정하지 않으므로, this는 곧 window 객체
    2. addEventListner 메서드는 콜백 함수 호출 시, 자신의 this를 상속하므로, this는 addEventListner의 앞부분 (button 태그)
  7. 생성자 함수 내부에서의 this

    1. 생성자 : 구체적인 인스턴스 (객체로 이해해도 된다.)를 만들기 위한 일종의 틀

    2. 공통 속성들이 이미 준비되어 있다.

      var Cat = function (name, age) {
      	this.bark = '야옹';
      	this.name = name;
      	this.age = age;
      };
      
      var choco = new Cat('초코', 7); //this : choco
      var nabi = new Cat('나비', 5);  //this : nabi
      

2. 명시적 this 바인딩