이게(this) 뭐야

Jinux·2022년 8월 26일
0

this

this는 무엇일까요?

자바스크립트에서 함수는 호출될 때, 매개변수로 전달되는 인자값 이외에, arguments 객체와 this를 암묵적으로 전달받습니다. 또 this는 함수 호출방식에 따라 this에 바인딩되는 객체가 달라집니다.

문제는 함수는 다양한 방식으로 호출할 수 있습니다. 그 말은 this가 가리키는 것은 호출 방식에 차이가 있다는 것입니다.

예시를 살펴봅시다

일반 함수 내부에서의 this

console.log(this);

function square(number){
    // 일반 함수 내부에서 this는 전역 객체 window를 가리킨다.
    console.log(this);
    return number * number;
}

square(2);

일반 함수 내부에서 this는 기본적으로 전역 객체인 window를 가리키는 것을 볼 수 있습니다. Node.js에서는 global을 가리키겠네요.

만약 함수안에 함수를 호출한다면 내부함수의 this는 어디에 바인딩이 될까요?

function foo() {
  console.log("foo's this: ",  this);  // window
  function bar() {
    console.log("bar's this: ", this); // window
  }
  bar();
}
foo();

내부 함수는 어디에서 선언되었든 this를 가리킵니다. 일반함수, 메소드, 콜백함수 어디에서든요.

메서드 호출의 this

만약 선언된 함수가 객체의 프로퍼티라면 메소드로 호출이 됩니다. 이 때 메소드의 this는 어디를 가리킬까요? 이것도 내부에 있으니 내부함수처럼 전역을 가리킬까요?

const person = {
    name: 'Jeong',
    getName() {
        // 메서드 내부에서 this는 메서드를 호출한 객체를 키리킨다.
        console.log(this);
        return this.name;
    }
};
console.log(person.getName());

메서드 내부의 this는 메서드를 호출한 객체가 바인딩되는 것을 볼 수 있습니다.

var obj1 = {
  name: 'Lee',
  sayName: function() {
    console.log(this.name);
  }
}

var obj2 = {
  name: 'Kim'
}

obj2.sayName = obj1.sayName;

obj1.sayName();
obj2.sayName();

위의 학습한 내용에 따라 위의 예시를 살펴보면 obj1에 sayName 메소드는 this를 통해 obj1객체를 가리키고 있음을 알 수 있습니다.

그렇다면 obj2 메소드에 같은 this를 호출하는 메소드를 넣어준다면? 잠깐 헷갈릴 수 있지만 obj2 또한 객체이고 그 안에 함수를 선언한다면 메소드입니다. 즉, obj2의 name을 가르키게 됩니다.

생성자 함수 호출

생성자 함수란 말 그대로 함수를 생성하는 역할을 하는데요. 자바와 같은 객체지향 언어의 생성자 함수와는 다르게 형식이 정해져있지는 않다고 합니다.

자바스크립트에서는 기존 함수에 new 연산자를 붙여 해당 함수를 생성자 함수로 동작하게 하죠.

function Person(name){
    this.name = name;
    // 생성자 함수 내부에서 this는 생성자 함수가 생성할 인스턴스를 가리킨다.
    console.log(this);
}

const me = new Person('Jeong');

// 만약 new 연산자를 붙이지 않는다면 생성자 함수로 동작하지 않습니다.
let me2 = Person('Kim');
console.log(me2); 

생성자 함수는 다음과 같은 순서로 동작합니다.

function Person(name) {
  // 생성자 함수 코드 실행 전 -------- 1
  this.name = name;  // --------- 2
  // 생성된 함수 반환 -------------- 3
}

var me = new Person('Lee');
console.log(me.name);
👉 1. 빈 객체 생성 및 this 바인딩

생성자 함수의 코드가 실행되기 전에 빈 객체를 생성합니다. 추후 이 빈 객체는 생성자 함수가 새로 생성하는 객체로 생성자 함수 내부에 this는 이 빈 객체를 가리킵니다. 그리고 빈 객체는 생성자 함수의 prototype 프로퍼티가 가르키는 객체를 자신의 프로토타입 객체로 설정합니다.

  1. 빈 객체 생성 (추후에 생성자 함수가 새로 생성하는 객체가 된다)
  2. 생성자 함수 내의 this는 아직은 빈 객체를 가리킴
  3. 빈 객체는 생성자 함수의 prototype 프로퍼티가 가리키는 객체를 자신의 프로토타입 객체로 설정합니다.
👉 2. this를 통한 프로퍼티 생성

생성된 빈 객체에 this를 사용하여 동적으로 프로퍼티나 메소드를 생성할 수 있습니다. this는 새로 생성하는 객체를 가리키고 이를 통해 프로퍼티와 메소드는 새로 생성된 객체에 추가됩니다.

👉 3. 생성된 객체 반환

반환문이 없는 경우, this에 바인딩된 새로 생성한 객체가 반환된다. 명시적으로 this를 반환하여도 결과는 같습니다. 만약 this가 아닌 다른 객체를 명시적으로 반환하는 경우, this는 해당 객체를 반환하지만 생성자 함수로서의 역할은 수행하지 못합니다. 따라서 생성자 함수는 반환문을 명시적으로 사용하지 않습니다.

생성자 함수로 만들어진 함수를 만약 new 를 붙이지 않고 호출한다면?

일반함수와 생성자 함수에 특별한 형식적 차이는 없습니다, 그저 new 연산자를 붙여 호출하면 생성자 함수로 동작할 뿐입니다.

객체 생성 목적으로 만들어진 생성자 함수를 new 없이 호출하거나 일반함수에 new를 붙여 호출하면 오류가 발생할 수 있습니다. 이는 앞서 알아본 바와 같이 this 바인딩 방식이 다르기 때문입니다.

이런 위험성을 회피하기 위해 사용하는 패턴 Scope-Sate Constructor이 있는데 이는 다음에 알아보도록 하겠습니다.

마무리

이 포스팅을 하며 도대체 this가 무엇인지 this에 대해 알아보았는데요. 정리하자면 자바스크립트에서의 this는 호출 하는 방식에 따라 다른 참조 값을 가집니다.

어떤 위치에 선언되있고, 어디에서 호출 등에 따라서요

일반 함수에서 호출된다면 this는 전역객체를
메소드로 호출된다면 해당 객체를
생성자 함수로 호출된다면 생성자 함수가 생성할 인스턴스를 가리킵니다.

지금까지 자바스크립트 엔진이 this를 참조하는 방식을 알아보았다면 다음엔 개발자가 this를 직접 참조해주는 방식을 알아보겠습니다. 바로 apply bind call 함수 입니다.

참고: 책- 모던자바스크립트 딥 다이브

0개의 댓글