Javascript의 this의 바인딩 룰

유다송·2023년 8월 8일
0

JavaScript

목록 보기
6/8
post-thumbnail

복습

  • 함수가 호출 되면 그때 그때 상황에 따라 this가 가리키는 객체가 결정된다.
  • 이렇게 함수가 호출 될 때마다 this가 동적으로 결정되는 것을 "this가 그 객체에 binding 된다"라고 표현한다.
  • 동작을 나타내는 메서드는 자신이 속한 객체의 상태, 즉 프로퍼티를 참조하고 변경할 수 있어야 한다. 그러기 위해서는 자신이 속한 객체를 가리키는 식별자를 참조할 수 있어야 한다.

this의 동적 바인딩

1. 일반 함수 호출

    function func(){
      console.log(this);
      function func2(){
        console.log(this);
      }
      func2(); // window
    }
    func(); // window
  • 일반 함수를 호출했을 때 전역객체인 window를 바인딩하게 됨.

그렇다면 객체의 메서드와 메서드 내부 함수의 this는 어떻게 다를까?

    var name = 'global var'; // 전역 객체
    const obj = { // 
      name:'Tom',
      say(){ // obj의 메서드. 자신이 속한 객체 obj를 참조하여 'Tom' 출력
        console.log('my name is ', this.name);

        function say2(){ // 메서드 내부 함수. 일반함수로 window 바인딩 'global var' 출력
          console.log('my name is ', this.name);
        }
        say2();
      }
    };

    obj.say();
    // my name is Tom
    // my name is global var
   var name = 'global var';
    const obj = {
      name:'Tom',
      say(){
        console.log('my name is ', this.name);
        const that = this;

        function say2(){
          console.log('my name is ', that.name); // that 키워드에 할당하면 내부함수에도 메서드 바인딩 가능
        }
        say2();
      }
    };

    obj.say();
    // my name is Tom
    // my name is Tom

- 화살표 함수 사용

var name = 'global var';
    const obj = {
      name:'Tom',
      say(){
        console.log('my name is ', this.name);

        const say2 = ()=> {
          console.log('my name is ', this.name);
        }
        say2();
      }
    };

    obj.say();
    // my name is Tom
    // my name is Tom

- apply, call, bind와 같은 빌트인 객체 프로토타입의 메서드들을 이용

    var name = 'global var';
    const obj = {
      name:'Tom',
      say(){
        console.log('my name is ', this.name);

        function say2(){
          console.log('my name is ', this.name);
        }
        say2.apply(this);
        say2.call(this);
      }
    };

    obj.say();
    // my name is Tom
    // my name is Tom
    // my name is Tom

2. 메서드 호출

    const obj = {
      name:'Tom',
      say(){
        console.log('my name is ', this.name);
      }
   };
    obj.say(); // my name is Tom
  • say 메서드에서 this가 이미 obj로 바인딩되어 있는것처럼 보이지만 사실은 메서드가 호출될 때 정해짐.
    const obj = {
      name:'Tom',
      say(){
        console.log('my name is ', this.name);
      }
   };
    obj.say(); // my name is Tom

    const obj2 = {
      name:'James',
    };

    obj2.__proto__.say = obj.say; // obj1이 가진 say 메서드를 obj2의 프로토타입 메서드에 추가
    obj2.say(); // my name is James (this가 obj2로 바인딩)
  • say 메서드는 obj 객체에 종속된 함수가 아니다.
  • obj 객체라는 공간이 있다면, say 프로퍼티가 있고, 그 프로퍼티가 어떤 공간을 가리킨다.
  • say 프로퍼티가 가리키는 공간에 함수가 정의되어 있을 것이며, say 함수의 구현을 담고 있다.
  • 프로토타입에 정의된 say 메서드는 obj2.say()로 호출 될 것이고, 호출시 동적으로 this가 바인딩되기 때문에 obj2 객체가 바인딩된다.

즉 메서드가 객체 내부에 종속된 것이 아님.

3. 생성자 함수 호출

    function Person(name){
      this.name = name;
      this.say = function(){
        console.log('my name is ', this.name);
      };
    }

    const tom = new Person('Tom'); // new 키워드의 결과로서 암묵적인 return this;를 실행
   console.log(tom) // Person {name: 'Tom', say: ƒ}

    const noTom = Person('Tom');
    console.log(noTom); // undefined (리턴이 없어 undefined가 반환되었다.)

4. Function.prototype.apply/call/bind 메서드에 의한 간접호출

    var fire = 'fail..';
    const thisObj = { fire : 'fire!' };
    function func(a,b,c){
        console.log(a,b,c, this.fire);
    }

    console.log(func(3,2,1)); // 3 2 1 fail..
    console.log(func.apply(thisObj, [3,2,1])); // 3 2 1 fire!, 인수를 배열 []로 묶어서 전달
    console.log(func.call(thisObj, 3, 2, 1)); // 3 2 1 fire!, 인수를 쉼표로 구분해서 전달
    console.log(func.bind(thisObj)); // this가 바인딩 된 함수 자체를 리턴
                                     //	ƒ func(a,b,c){
                                     //   console.log(a,b,c, this.fire);
                                     //	  }

    const bindFunc = func.bind(thisObj, 100); // 첫번째 인자로 this에 바인딩할 객체를 받으며
											  // 두번째 인자부터는 함수 자체에서 받는 인자의 값을 미리 설정할 수 있다.
    bindFunc(2, 1); // 100 2 1 fire!

자바스크립트 this
함수 호출 방식과 this 바인딩
this 바인딩 정리

1개의 댓글

comment-user-thumbnail
2023년 8월 8일

이렇게 유용한 정보를 공유해주셔서 감사합니다.

답글 달기