ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Section 12. 자바스크립트 this의 동적 바인딩
    자바스크립트 2023. 4. 7. 17:50

    I. this - "이곳의~"

    • 기본적으로 자신이 속한 곳을 가리킨다.
    • 함수의 호출 방식에 따라 가리키는 바가 달라진다. - 자바스크립트 특성

     

    1. 전역에서의 this

    • 브라우저의 콘솔창 : window 객체 - globalThis와 같음
    • Node.js의 REPL: global 객체 - globalThis와 같음
    • .js 문서로 작성 후 실행 - 빈 객체가 나온다.
    • 이유는 Node.js에서 각 .js문서들은 모듈로서 실행되기 때문이다.

     

    2. 함수 안에서의 this

    느슨한 모드와 엄격 모드에서 다르게 동작한다.

    function func () {
      console.log(this); // globalThis
    }
    
    func(); //Window 객체
    'use strict';
    
    function func () {
      console.log(this); // undefined
    }
    
    func(); //undefined

    객체에 속하지 않은 함수에서는 this 사용이 의미 없다.

     

    3. 객체 안에서의 this

    a. 객체 리터럴 - 해당 객체를 가리킨다.

    const obj = {
      x: 123,
      getX: function () {
        return this.x;
      }
    }
    
    console.log(obj.getX()); //123

     

    b. 생성자 함수 - 생성될 인스턴스를 가리킨다.

    function Person (name, age) {
      this.name = name;
      this.age = age;
      this.introduce = function  () {
        return `저는 ${this.name}, ${this.age}세입니다.`
      }
    }
    
    console.log(
      new Person('홍길동', 20).introduce()
    ); //저는 홍길동, 20세입니다.

     

    c. 클래스 선언 - 생성될 인스턴스를 가리킨다.

    class KangChicken {
      constructor (name, no) {
        this.name = name;
        this.no = no;
      }
      introduce () {
        return `안녕하세요, ${this.no}호 ${this.name}점입니다!`;
      }
    }
    
    console.log(
      new KangChicken('강남', 17).introduce()
    );

     

    II. 동적 바인딩

    • 자바스크립트의 독특한 동작방식이다.
    • this가 가리키는 대상이 함수의 호출 주체 또는 그 방식에 따라 달라진다.
    const korean = {
      favorite: '김치',
      makeStew: function (isHot, pots) {
        return `${isHot ? '매운' : '순한'} ${this.favorite}찌개 ${pots}냄비`;
      }
    };
    
    const italian = {
      favorite: '피자'
    };
    console.log(
      korean.makeStew(true, 1)
    ); //매운 김치찌개 1냄비

    만약 makeStew프로퍼티를 italian에게 할당을 하면 다음과 같다

    // 이탈리아인에게 한국인이 찌개 끓이는 법을 알려줌
    italian.makeStew = korean.makeStew;
    
    console.log(
      italian.makeStew(false, 2)
    ); //순한 피자찌개 2냄비

    같은  this를 썻지만 this가 가리키는 것이 korean에서 italian으로 바뀐 것을 볼 수 있다.

     

    함수가 누가, 어떻게 호출되었는가에 따라 this가 가리키는 대상이 달라진다.

     

    해결방법들

    1. call를 사용한 함수 호출

    this의 대상과 인자들을 나열한다.

    console.log(
      italian.makeStew.call(korean, false, 2)
    ); //순한 김치찌개 2냄비

    2. apply를 사용한 함수 호출

    this의 대상 뒤의 인자들을 배열로 넣어준다.

    console.log(
      italian.makeStew.apply(korean, [false, 2])
    ); //순한 김치찌개 2냄비

    3. bind를 사용한 this 대상을 고정한다.

    this의 대상이 동적으로 변하지 않는 함수를 반환한다.

    // ⭐ this가 바인딩된 새 함수를 만듦
    italian.makeRightStew = korean.makeStew.bind(korean);
    
    console.log(
      italian.makeRightStew(false, 2)
    );

    추가 인자들까지 바인딩이 가능하다

    italian.makeClassicStew = korean.makeStew.bind(korean, true, 1);
    
    console.log(
      italian.makeClassicStew()
    ); //매운 김치찌개 1냄비

    4. 바인딩된 함수를 내보내는 함수

    const korean = {
      favorite: '김치',
      makeStew: function (isHot, pots) {
        return `${isHot ? '매운' : '순한'} ${this.favorite}찌개 ${pots}냄비`;
      },
      teachMakingStew: function () {
        return this.makeStew.bind(this);
      }
    };
    
    const italian = {
      favorite: '피자'
    };
    italian.makeStew = korean.teachMakingStew();
    
    console.log(
      italian.makeStew(false, 2)
    ); //순한 김치찌개 2냄비

    5. 생성자 함수일 경우 - 함수 자체를 미리 인스턴스에 바인딩하기

    function Korean () {
      this.favorite = '김치';
      this.makeStew = function (isHot, pots) {
        return `${isHot ? '매운' : '순한'} ${this.favorite}찌개 ${pots}냄비`;
      };
    
      // 💡 여기서 바인딩을 고정시켜버림
      this.makeStew = this.makeStew.bind(this);
    }
    
    function Italian () {
      this.favorite = '피자';
    }
    const korean = new Korean();
    const italian = new Italian();
    
    italian.makeStew = korean.makeStew;
    
    console.log(
      italian.makeStew(false, 2)
    ); //순한 김치찌개 2냄비

     

    배열 메서드의 thisArg

    • 콜백으로 주어진 함수 내에서 this가 가리킬 대상.
    • 보통 콜백함수 다음 인자로 넣는다.
    function recommendForYou (me) {
      const products = [
        { sex: 'F', size: 'M' },
        { sex: 'M', size: 'L' },
        { sex: 'F', size: 'M' },
        { sex: 'U', size: 'S' },
        { sex: 'M', size: 'L' },
        { sex: 'F', size: 'S' },
      ];
    
      products
      .map((itm, idx) => {
        return { ...itm, idx } 
      })
    
      // ⚠️ 화살표 함수 대신 function 선언 함수 사용 주목
      .filter(function ({sex, size}) {
        return ['U', this.sex].includes(sex)
        && size === this.size
      }, me) // 💡 thisArg
    
      .forEach(function ({idx}) {
        console.log(`${this.name}님, ${++idx}번은 어떠세요?`);
      }, me); // 💡 thisArg
    }
    const peter = {
      name: '피터',
      sex: 'M',
      size: 'L'
    };
    
    const jane = {
      name: '제인',
      sex: 'F',
      size: 'S'
    };
    recommendForYou(peter);
    recommendForYou(jane);
    
    //피터님, 2번은 어떠세요?
    //피터님, 5번은 어떠세요?
    //제인님, 4번은 어떠세요?
    //제인님, 6번은 어떠세요?
Designed by Tistory.