# 2. this가 이런거로군

## 주요 개념 및 내용

1장에서 언급했듯이 호출하는 시점이 중요!\
그 연장선으로 4가지 규칙 암기 함수호출은 `callstack`구조로 쌓이게 되므로 그 호출 순서도 중요

### this가 바인딩 되는 규칙

* **명시적**

  객체를 명확히 전달함

  * call, apply(obj,배열타입), bind

    ```javascript
    function foo() {
    console.log(this.a);  // this = obj
    };
    var obj = {a:2};
    foo.call(obj);    // 2 : 객체(obj)를 명시적으로 넘김 

    // 객체가 아닌 원시값 (String, Number, Boolean) 넘기 경우 -> new String(), new Number(), new ~ 호출
    ```
  * 하드바인딩 소실되는 경우 this를 완전 명확히 바인딩 시킴 (꼼수)

    ```javascript
      function foo4() {
          console.log(this.a);
      }

      var obj33 = {
          a: 25
      };
      var bar = function () {
          foo.call(obj33);  //  하드바인딩
      };

      bar();  //25
    ```
* **new `6장 프로토타입에서 보강`**

  JS `new` **class 지향과 무관**\
  일반함수에 불과 !!\
  `new -> 함수를 생성하는 호출` (새객체가 만들어진다! -> this로 바인딩된다!)

  ```javascript
    function foo44(a) {
      this.a = a;   // this -> 새로 생성된 객체를 가르킨다  this = bar
    }

    var bar = new foo44(22);
    console.log(bar.a); // 22 : this = bar (new for44-> 새객체(함수) 생성 -> bar에 바인딩)
  ```
* **암시적**

  컨텍스트 객체를 통한 바인딩

  ```javascript
    function foo2() {
      console.log(this.a);  // this = obj
    };
    var obj2 = {
        a: 42,
        foo2: foo2
    };

    var obj = {
        a: 4,
        foo2: foo2,  // obj.foo2 = foo2
        obj2: obj2
    };

    obj.foo2(); // 4
    obj.obj2.foo2();  // 42 : 하부에서부터 탐색을하기 때문

    var bar = obj.foo2;
    var a = "전역쓰~";
    // 암시적 소실 -> obj가 객체가 아님
    bar();  // undefined -> 이때 호출은 그냥 foo2 호출가 동일해지면서 기본바인딩 적용 : this = global ()
  ```
* **기본**

  &#x20; 가장 기본규칙 렉시컬 스코프&#x20;

  ```javascript
    function foo(){
        console.log(this.a); // this => global 
    }
    var a = 2;  //
    foo(); // undefined / 엄격모드:에러 -> 호출스코프 : 전역, foo this -> global
  ```

### 주의 사항

* **바인딩 우선순위**

  ```
    명시(하드) > new > 암시 > 기본 순서
  ```
* **예외 사항**
  * **this 무시**

    : null, undefined 인자로 -> `기본바인딩 적용`

    ```javascript
    function foo55() {
      console.log(this.a55);
    }

    var a55 = 2;
    foo55.call(null); // this 무시  : this -> global
    foo55.call(a55);  // ?? 원시 값 a55 -> Number -> this? prototyp
    ```
  * **간접레퍼런스**

    참조값을 통해 호출되므로 원 함수를 가르키게 되는 상항 -> this는 그래서 `기본바인딩`이 이루어짐
  * **소프트 바인딩**

### 테스트 코드

```javascript
(function () {

  // 기본 바인딩
  console.log("====== 기본 바인딩 ======");
  function foo() {
    console.log(this.a);  // 함수 자신 아님, this = global
  }
  var a = 2;
  foo();  // undefined

  // 암시적 바인딩
  console.log("====== 암시적 바인딩 ======");
  function foo2() {
    console.log(this.a);  // this = obj
  }

  var obj2 = {
    a: 42,
    foo2: foo2
  };

  var obj = {
    a: 4,
    foo2: foo2,  // obj.foo2 = foo2
    obj2: obj2
  };

  obj.foo2(); // 4
  obj.obj2.foo2();  // 42

  var bar = obj.foo2;
  var a = "전역쓰~";
  bar();  // undefined -> 이때 호출은 그냥 foo2 호출가 동일해지면서 기본바인딩 적용 : this = global

  // 명시적 바인딩
  console.log("====== 명시적 바인딩 ======");
  function foo3() {

    console.log(this.a);  // this = obj3
  }
  var obj3 = {
    a: 30
  };

  foo3.call(obj3); // 30 (obj3 명시)

  // 하드 바인딩
  console.log("====== 하드 바인딩 ======");
  function foo4() {

    console.log(this.a);
  }
  var obj33 = {
    a: 25
  };

  var bar = function () {
    foo.call(obj33);  //  하드바인딩
  };
  bar();  //25


  // new 바인딩
  console.log("====== new  바인딩 ======");
  function foo44(a) {

    this.a = a;   // this -> 새로 생성된 객체를 가르킨다  this = bar
  }
  var bar = new foo44(22);

  console.log(bar.a); // 22 : this = bar (new for44-> 새객체(함수) 생성 -> bar에 바인딩)


  // this 무시
  console.log("====== this 무시 ======");
  function foo55() {
    console.log(this.a55);
  }

  var a55 = 2;
  foo55.call(null); // this 무시  : this -> global
  foo55.call(a55);  // ??




  // 에로우 함수의 this -> 전역객체를 따른다 -> 사용하지말자
  console.log("======= 에로우 함수 =======");
  function foo5() {
    return (a) => {
      console.log(this.a);
    };
  }

  var obj = {a: 1};
  var obj2 = {a: 2};

  var bar = foo5.call(obj);
  bar.call(obj2);

  // setTimeout에서의 에로우 함수 this 활용한 꼼수
  function foo6() {
    setTimeout(() => {
      console.log(this.a);
    }, 100);
  }

  var obj3 = {a: 3};
  foo6.call(obj3);


  // var self = this를 활용한 꼼수
  function foo7() {
    var self = this;
    setTimeout(function () {
      console.log(self.a);
    },100);
  }

  var obj4 = {a: 4};
  foo7.call(obj4);

})();
```
