3 분 소요

Javascript 개념

모던 자바스크립트 딥 다이브 정리

this

this

this란?

자신이 속한 객체 또는 자신이 생성할 인스턴스를 가리키는 자기 참조 변수(self-referencing variable)이다.
이를 이용해 자신이 속한 객체/인스턴스의 메서드, 프로퍼티를 참조할 수 있다.

객체 리터럴 방식으로 객체를 생성하면 이미 객체 이름이 메모리에 있는 것 이기 때문에, 메서드 안에서 객체를 재귀적으로 참조할 수 있다.

하지만, 이것 또한 바람직하지 않다.

또한, 생성자 함수 방식으로 인스턴스를 생성하면 생성자 함수를 정의할 때에는 인스턴스가 아직 없기 때문에 인스턴스를 가리킬 수 있는 식별자가 없다.

이를 위해 자바스크립트에서는 this를 제공한다.

  • this 용법

    this는 사용 시 호출한 방법에 따라 결정되는 것

자바스크립트에서 this는 호출하는 방법에 따라 결정되며 strict mode 에 따라 달라지기도 한다.

  • 함수 호출 방식에 따른 this 바인딩 this 바인딩은 함수 호출 방식에 따라, strict mode에 따라 동적으로 결정된다.
    1. 일반 함수 호출

      기본적으로 this에는 전역 객체(global object)가 바인딩된다.

      따라서, 함수 안에 this를 사용하고 일반 함수로 호출했을 때 전역 객체가 바인딩된다.(browser → window/ nodeJS → global)

      함수의 내부 함수(중첩 함수) 혹은 콜백 함수 안의 this 또한 전역 객체가 바인딩된다.

      strict mode가 적용되면 일반 함수 내부에서 this는 undefined가 바인딩된다.

    2. 메서드 호출

      메서드를 호출할 때 메서드 (./마침표) 연산자 앞에 기술한 객체가 바인딩된다.

      이 때 this는 메서드를 소유한 객체가 아닌 메서드를 호출한 객체에 바인딩된다.

    3. 생성자 함수 호출

      생성자 함수가 생성할 인스턴스가 바인딩된다.

      생성자 함수는 객체(인스턴스)를 생성하는 함수이다. new와 함께 호출하면 생성자 함수로 호출이 되는데,

      이 때 this는 생성하게 될 인스턴스가 바인딩된다.

    4. 화살표 함수(arrow function)에서 사용하는 this

      화살표 함수에서 this는 자신을 감싼 정적 범위이다. 전역에 있다면 전역 객체를 가리키게 되는 것.

       let globalObject = this // 전역이니까 window(브라우저에서)
       let foo = () => this // 전역이니까 자신을 감싼 범위 => window
       console.log(foo() === globalObject) // true
              
       // 객체로서 메서드 호출
       var obj = { func: foo }
       console.log(obj.func() === globalObject) // true
              
       // call을 사용한 this 설정 시도
       console.log(foo.call(obj) === globalObject) // true
              
       // bind를 사용한 this 설정 시도
       foo = foo.bind(obj)
       console.log(foo() === globalObject) // true
      

      위 처럼 어떤 메소드를 사용해서 this 값을 호출하더라도 무시한다.

    5. 클래스 (생성자)에서의 this

      생성하게 될 인스턴스를 this에 바인딩한다.

    6. DOM 이벤트 처리기에서의 this

      함수를 이벤트 처리기로 사용하면 this는 이벤트를 발사한 요소로 설정한다.

       function curF(e) {
         // 언제나 true
         console.log(this === e.currentTarget); // currentTarget 지금 이벤트를 발생시킨 요소
         // currentTarget과 target이 같은 객체일 경우에만 true
         console.log(this === e.target);
       }
      
    7. 메서드에 의한 간접 호출

      Call, Apply, Bind 메서드를 통해 this를 바인딩한다.

  • Call, Apply, Bind 메서드 this에 특정값을 지정해주는 메서드

    • Call call 메서드는 모든 함수에서 사용할 수 있으며 this를 특정값을 지정할 수 있다.

      const mike = {
        name: "mike",
      };
      const tom = {
        name: "tom",
      };
      
      function showThisName() {
        console.log(this.name); // 해당 객체의 name 값을 console로 띄워라.
      }
      
      showThisName(); // 이렇게 아무 매개변수 없이 호출하면
      // 저기서 this가 가리키는 것은 여기서 window 이므로
      // window.name은 정의되어 있지 않으니 undefined 출력하지 않는다.
      showThisName.call(mike); // mike 나옴
      // 함수를 사용하면서 call을 하고 this로 사용할 객체를 넘기면
      // 해당 함수가 주어진 객체의 메서드인 것처럼 사용할 수 있다.
      

      그냥 함수 호출한 경우와 call하여 mike를 객체로 전달한 것과의 차이로 call을 이해할 수 있다. call을 이용해서 mike를 this로 사용할 수 있도록 해주면 mike.name을 나타낼 수 있는 것이다. 위의 코드에 이어서, update라는 생성자를 만들어 call을 통해 객체를 업데이트할 수 있다.

      function update(birthYear, occupation) {
        this.birthYear = birthYear;
        this.occupation = occupation;
      }
      
      update.call(mike, 1999, "singer");
      console.log(mike); // { name: 'mike', birthYear: 1999, occupation: 'singer' }
      // update를 call하고 나머지 객체를 전달해주니까
      // update에서는 전달받은 객체를 this로 사용하고, 그 객체의 birthYear, ocuupation을 각각의 값으로 지정한다.
      

      this를 mike로 사용할 수 있도록 mike를 전달해주고, 나머지 객체들을 전달해주니 원래의 객체에 속성이 추가된 것을 확인할 수 있다.

    • Apply call과 거의 같지만, 매개변수를 배열로 받는다. 함수 매개변수를 배열로 사용할 때 유용하다.

      const tom = {
        name: "tom",
      };
      
      function update(birthYear, occupation) {
        this.birthYear = birthYear;
        this.occupation = occupation;
      }
      
      update.apply(tom, [2002, "teacher"]);
      console.log(tom); // { name: 'tom', birthYear: 2002, occupation: 'teacher' }
      
    • Bind

      const mike = {
        name: "mike",
      };
      
      function update(birthYear, occupation) {
        this.birthYear = birthYear;
        this.occupation = occupation;
      }
      
      const updateMike = update.bind(mike);
      updateMike(1980, "police");
      console.log(mike); // { name: 'mike', birthYear: 1980, occupation: 'police' }
      

      bind는 항상 mike를 this로 받겠다고 하는 것. (사실 bind는 지정된 this를 가지는 함수를 반환해준다.) 따라서, updateMike에 첫번째 인자로 굳이 mike 객체라고 명시해주지 않아도 this는 mike로 이미 영구히 지정되어있다.

댓글남기기