Tech

Diary

Lecture

개발중

About Me

개발중

상황에따른 this 정리

JeongSeulho

2024년 04월 07일

준비중...
클립보드로 복사
thumbnail

1. this란

모든 함수는 this를 가지고 있으며 this는 어떤 객체를 가르키고 있다. 그리고 this는 함수가 호출되는 상황에 따라 가리키는 어떤 객체가 달라진다.
이렇게 함수가 호출되는 상황에 따라 this가 가리키는 객체가 동적으로 변하는데, 이를 this가 어떤 객체에 바인딩되는 것이라고 한다.

2. this binding rules

this가 어떤 객체를 가리키는지는 아래에서 설명할 규칙에 따라 달라진다.

2.1 기본 바인딩

기본 바인딩은 어떤 객체를 통해 함수가 호출되지 않고 함수가 단독으로 호출되었을 때 규칙이다.

  • 브라우저

    • strict mode인 경우와 아닌 경우의 차이가 있다.
    copy
    function a(){
      console.log(this);
    }
    
    function b(){
      'use strict';
      console.log(this);
    }
    
    a(); // object [window]
    
    console.log(this); // object [window]
    
    b(); // undefined
  • Node.js

    • 전역 컨텍스트에서 실행되는 경우와 어떤 함수 컨텍스트에서 실행되는 경우의 차이가 있다.
    copy
    function a(){
      console.log(this);
    }
    
    // 함수 컨텍스트
    a(); // object [global]
    
    // 전역 컨텍스트
    console.log(this); // {}
    
    console.log(this === module.exports); // true

2.2 암시적 바인딩

함수가 어떤 객체의 메소드로 호출되었을 때, this는 해당 객체를 가리킨다.
하지만, 메소드가 파라미터로 전달되거나 다른 변수에 할당되어 호출되는 경우 암시적 바인딩이 적용되지 않는다.

copy
const obj = {
  name: 'seulho',
  getName: function(){
    console.log(this.name);
  }
}

function execute(callback){
  callback();
}

obj.getName(); // seulho

// 파라미터로 전달, 암시적 바인딩 적용 X
execute(obj.getName); // undefined

// 변수에 할당, 암시적 바인딩 적용 X
const getName = obj.getName;
getName(); // undefined

. 또는 [] 연산을 사용하여 객체의 속성에 접근하면 참조 타입이라고 하는 어떤 값을 얻게 된다.
이 값에 메소드가 호출된 객체가 있으며 암시적 바인딩이란 이 정보를 사용하여 this를 바인딩한다.
위 처럼 파라미터, 변수에 할당을 하게 되면 이 정보들이 같이 전달되지 않고 해당 메소드의 참조값만 전달되기 때문에 this가 바인딩 되지 않는다.

2.3 명시적 바인딩

call, apply, bind 메소드를 사용하여 this를 바인딩하는 것을 명시적 바인딩이라고 한다.

copy
const obj = {
  name: 'seulho',
  getName: function(arg1, arg2){
    console.log(this.name, arg1, arg2);
  }
}

const obj2 = {
  name: 'seulho2'
}

// obj2를 바인딩하여 호출
obj.getName.call(obj2, 'arg1', 'arg2'); // seulho2 arg1 arg2
obj.getName.apply(obj2, ['arg1', 'arg2']); // seulho2 arg1 arg2

// 항상 obj2를 바인딩하는 새로운 함수 생성
// 하드 바인딩
const getNameBindObj2 = obj.getName.bind(obj2, 'arg1', 'arg2');
getNameBindObj2(); // seulho2 arg1 arg2

2.4 new 바인딩

함수에 new 키워드를 사용하면 3가지 일이 일어난다.

  1. 새로운 객체가 생성된다. => 여기서 this는 새로 생성된 객체를 가리킨다.
  2. 함수 코드가 실행
  3. 생성된 새로운 객체 반환

즉, new를 사용하면 this는 새로 생성된 객체를 가리킨다.

copy
function Person(name){
  this.name = name;
  getName = function(){
    console.log(this.name);
  }
}

const person = new Person('seulho');
person.getName(); // seulho

const person2 = new Person('seulho2');
person2.getName(); // seulho2

3. this 바인딩 우선순위

위의 바인딩 규칙은 중복으로 적용되는 경우가 많은데, 이때 this 바인딩 우선순위는 아래와 같다.

  1. new 바인딩
  2. 명시적 바인딩
  3. 암시적 바인딩
  4. 기본 바인딩

4. 화살표 함수와 this

화살표 함수의 this는 함수가 호출 기준이 아닌 선언될 당시의 상위 실행 컨텍스트의 this를 가리킨다.

copy
const obj = {
  name: 'seulho',
  getNameInSec() {
    setTimeout(function(){
      console.log(this.name);
    }, 1000);
  }
}

obj.getNameInSec(); // undefined

위와 같이 함수가 파라미터로 전달되었기 때문에 this는 암시적 바인딩이 적용되지 않아 window 또는 Timeout 객체를 가리키게 된다.

  • 지역 변수를 사용하여 해결

    copy
    const obj2 = {
      name: 'seulho',
      getNameInSec() {
        const that = this;
        setTimeout(function(){
          console.log(that.name);
        }, 1000);
      }
    }
    
    obj2.getNameInSec(); // seulho
  • bind를 사용하여 해결

    copy
    const obj3 = {
      name: 'seulho',
      getNameInSec() {
        setTimeout(function(){
          console.log(this.name);
        }.bind(this), 1000);
      }
    }
  • 화살표 함수를 사용하여 해결

    copy
    const obj4 = {
      name: 'seulho',
      getNameInSec() {
        setTimeout(() => {
          console.log(this.name);
        }, 1000);
      }
    }
    
    obj4.getNameInSec(); // seulho