ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • JS Deep Dive 22장. this
    개발/자바스크립트로의 깊은 잠수 2026. 7. 14. 20:43

    This와 그 파생의 용법. 이 글과는 별로 관련이 없다. 출처: https://english.eagetutor.com/spoken-english-grammar/the-right-use-of-this-that-these-those

     

    충격적인 코드를 하나 보면서 시작해 봅시다..

    const circle = {
      radius: 5,
      getDiameter() {
        return 2 * circle.radius; // 이 객체가 할당될 식별자 이름 circle을 미리 참조하고 있다!
      }
    };
    
    circle.getDiameter();
    

    이런 짓이 가능하다는 것에 적잖은 충격을 받았지만…

    아무튼 위와 같이 객체 리터럴로 인스턴스를 생성하면 같은 형태의 인스턴스들을 많이 뽑아내는 것이 어렵습니다.

    radius 프로퍼티와 getDiameter() 메서드를 가진 인스턴스를 여러 개 만드려면 매번 똑같은 객체를 다시 적어줘야 하기 때문에 코드 중복이 너무 많겠죠.

    그래서 본래 목적대로 효율적인 재사용을 하기 위해서는 생성자 함수 또는 (추후 배울) class를 사용해서 인스턴스를 만들어야 합니다.

    생성자 함수로 인스턴스를 만드려면 먼저 생성자 함수가 정의되어 있어야 합니다. 그런데 생성자 함수를 정의하는 시점에는 어떤 식별자(변수)에 인스턴스가 할당될지 미리 알 수가 없습니다. 위의 충격적인 코드와는 다르게 말이죠!

    그래서 자바스크립트는 자기 참조 변수 this라는 것을 제공합니다.

     

    this란 무엇인가.

    this는 자신이 속한 객체 또는 자신이 생성할 인스턴스를 가리키는 자기 참조 변수입니다. this를 통해 자신이 속한 객체, 또는 자신이 생성할 인스턴스의 프로퍼티나 메서드를 참조할 수 있습니다.

    function Circle(radius) {
      this.radius = radius;
    }
    Circle.prototype.getDiameter = function() {
      return 2 * this.radius; // this는 생성될 인스턴스를 가리킵니다.
    }
    
    const circle = new Circle(5);
    circle.getDiameter(); // 10
    

    재미있는 것은 this 바인딩, 즉 this가 가리키는 것은, 함수가 호출되는 방식에 따라 동적으로 결정된다는 사실입니다.

    호출 방식에 따라 달라지는 this를 누려보러 가봅시다…

     

    호출 방식에 따라 다른 것을 가리키는 this

    함수를 호출하는 방식은 아래 네 가지가 있습니다.

    1. 일반 함수 호출
    2. 메서드 호출
    3. 생성자 함수 호출
    4. Function.prototype.apply/call/bind 메서드에 의한 간접 호출

    하나씩 살펴보겠습니다.

    일반 함수로 호출하면 this에는 전역 객체가 바인딩됩니다.

    그게 중첩되어있든, 콜백함수에 들어가있든 말입니다…

    function foo() {
      this; // window
      function bar() {
        this; // window
      }
      bar();
    }
    foo();
    

    주의할 점은 strict mode를 쓰면 undefined가 바인딩됩니다. 보통 this라는 녀석은 전역 객체를 참조하기 위해 사용되지는 않기 때문에, 이런 안전 장치를 strict mode에서는 적용한 것이 아닌가 싶습니다.

    어떤 경우에 잘못 쓸 수 있느냐면, 아래와 같은 경우입니다.

    // 메서드 내부에 정의한 중첩 일반함수,
    // 콜백 함수가 일반함수로 호출되는 경우
    const obj = {
      value: 1,
      method() {
        function inner() {
          console.log(this.value); // undefined
        }
        
        setTimeout(function () {
          console.log(this.value); // undefined
        });
        
        inner();
      },
    };
    
    obj.method();

     

    요런 실수를 하지 않기 위해서는 이런 방법이 있습니다:

    1. 화살표 함수 사용

    화살표 함수는 자신만의 this를 만들지 않습니다. 바깥 함수의 this를 그대로 사용합니다.

    const obj = {
      value: 1,
    
      method() {
        const inner = () => {
          console.log(this.value); // 1
        };
    
        setTimeout(() => {
          console.log(this.value); // 1
        });
    
        inner();
      },
    };
    
    obj.method();

    2. bind 사용

    bind를 사용하면 함수의 this를 직접 지정할 수 있습니다.

    const obj = {
      value: 1,
    
      method() {
        function inner() {
          console.log(this.value); // 1
        }
    
        setTimeout(
          function () {
            console.log(this.value); // 1
          }.bind(this)
        );
    
        inner.bind(this)();
      },
    };
    
    obj.method();

    3. this를 변수에 저장

    바깥 함수의 this를 변수에 저장한 뒤 사용할 수도 있습니다.

    const obj = {
      value: 1,
    
      method() {
        const self = this;
    
        function inner() {
          console.log(self.value); // 1
        }
    
        setTimeout(function () {
          console.log(self.value); // 1
        });
    
        inner();
      },
    };
    
    obj.method();

    일반적으로는 가장 간단한 화살표 함수를 많이 사용합니다.

     

     

    메서드 내부의 this 역시 생성될 인스턴스를 가리킵니다. 그리고 그것은 동적으로 결정됩니다.

    const person = {
      name: 'Lee',
      getName() {
        return this.name;
      }
    };
    
    person.getName(); // Lee
    
    const anotherPerson = { name: 'Kim' };
    anotherPerson.getName = person.getName;
    anotherPerson.getName(); // Kim
    

    이게 가능한 이유는 this가 호출되는 시점에 자신을 호출한 객체를 참조하기 때문입니다.

    prototype 메서드의 경우에도 마찬가지입니다.

     

     

    댓글

Copyright 2022. ProdYou All rights reserved.