2. this가 이런거로군

주요 개념 및 내용

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

this가 바인딩 되는 규칙

  • 명시적

    객체를 명확히 전달함

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

      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를 완전 명확히 바인딩 시킴 (꼼수)

        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로 바인딩된다!)

      function foo44(a) {
        this.a = a;   // this -> 새로 생성된 객체를 가르킨다  this = bar
      }
    
      var bar = new foo44(22);
      console.log(bar.a); // 22 : this = bar (new for44-> 새객체(함수) 생성 -> bar에 바인딩)
  • 암시적

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

      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 ()
  • 기본

    가장 기본규칙 렉시컬 스코프

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

주의 사항

  • 바인딩 우선순위

      명시(하드) > new > 암시 > 기본 순서
  • 예외 사항

    • this 무시

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

      function foo55() {
        console.log(this.a55);
      }
      
      var a55 = 2;
      foo55.call(null); // this 무시  : this -> global
      foo55.call(a55);  // ?? 원시 값 a55 -> Number -> this? prototyp
    • 간접레퍼런스

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

    • 소프트 바인딩

테스트 코드

(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);

})();

Last updated