[JS] 자바스크립트 this

HP :) 😃·2022년 5월 6일
0
post-thumbnail

안녕하세요 hp입니다 :)

오늘은 자바스크립트에서 가장 중요하고 면접에서도 많은 질문이 나오는 this에 대해서 공부해보겠습니다.

📚 개념

자바스크립트에서 this란 자신이 속한 객체 또는 자신이 생성할 인스턴스를 가리키는 자기 참조 변수입니다.

this는 함수 호출 방식 , 즉 함수가 어떻게 호출되었는지에 따라 동적으로 결정됩니다.
호출하는 방식은 아래와 같습니다.

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

일반 함수 호출 ( 기본 바인딩 )

먼저 일반 함수 호출부터 알아보겠습니다.

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

위에 예제처럼 일반함수로 호출하면 전역함수나 중첩함수 모두 this는 window를 가리키는것을 알 수 있습니다.

메서드 호출 ( 암시적 바인딩 )

메서드 내부의 this에는 메서드를 호출할 때 메서드 이름 앞 마침표(.) 연산자 앞에 기술한 객체가 바인딩됩니다.

const obj ={
  name : 'hp',
  getName(){
    console.log(this); // obj
  }
}
obj.getName();

위와 같이 getName을 호출할때 obj를 이용해서 호출하였으므로 this는 obj 객체를 가리키는것을 알 수 있습니다.

또 다른 예제를 살펴보겠습니다.

const obj ={
  name : 'hp',
  foo(){
    console.log(this);  // obj
    function bar(){
      console.log(this); // window
    }
    bar();
  }
}
obj.foo();

첫번째 this는 2번째 케이스인 메서드 호출 케이스와 같아서 this는 obj를 가리키고 두번째 this는 1번째 케이스인 일반 함수 호출 케이스와 같아서 window를 가리킵니다.

만일 내부함수의 this가 전역객체를 참조하는 것을 회피하고 싶다면 아래와 같은 방법으로 사용됩니다.

const obj = {
  name: "hp",
  foo() {
    const that = this;

    console.log(this); // obj
    function bar() {
      console.log(that); // obj
    }
    bar();
  },
};
obj.foo();

생성자 함수 호출 ( new 바인딩 )

생성자 함수 내부의 this에는 생성자 함수가 생성할 인스턴스가 바인딩됩니다.

function Circle(r){
  this.r = r;
  this.getRadius = () => {
    console.log(this);
  }
}

const circle1 = new Circle(5);
console.log(circle1.getRadius()); // r=5인 Circle 객체를 가르킴

apply / call / bind 메서드에 의한 간접 호출 ( 명시적 바인딩 )

apply , call 메서드는 this로 사용할 객체와 인수 리스트를 인수로 전달받아 함수를 호출합니다.

function getThisBinding(){
  return this;
}

const thisArg = { a : 1 };

console.log(getThisBinding()); // window

console.log(getThisBinding.apply(thisArg)); // thisArg 객체
console.log(getThisBinding.call(thisArg)); // thisArg 객체

위와 같이 첫번째 console.log 에서는 위에서 봤던것 처럼 일반함수 호출 케이스와 같이 window를 가리키고 apply와 call 메서드를 이용한 console.log는 객체를 가리키는것을 알 수 있습니다.

apply와 call 메서드는 호출할 함수에 인수를 전달하는 방식만 다를 뿐 동일하게 동작합니다.

function getThisBinding(){
  console.log(arguments);
  // Arguments(3) [1, 2, 3, callee: ƒ, Symbol(Symbol.iterator): ƒ]
  return this;
}

const thisArg = { a : 1 };

console.log(getThisBinding.apply(thisArg , [1,2,3])); // thisArg 객체
console.log(getThisBinding.call(thisArg , 1,2,3)); // thisArg 객체

apply는 호출할 함수의 인수를 배열로 묶어서 전달하고 call은 호출할 함수의 인수를 쉼표로 구분한 리스트 형식으로 전달합니다.

apply와 call 메서드는 대표적인 용도로 arguments 객체와 같은 유사 배열 객체에 배열 메서드를 사용하는 경우가 있습니다.

bind메서드는 apply와 call 메서드와 달리 함수를 호출하지 않습니다. 하지만 첫 번째 인수로 전달한 값으로 this 바인딩이 교체된 함수를 새롭게 반환합니다.

function getThisBinding(){
  return this;
}

const thisArg = { a : 1 };

console.log(getThisBinding.bind(thisArg)); // getThisBinding 함수
console.log(getThisBinding.bind(thisArg)()); // thisArg 객체

bind 메서드는 대표적인 용도로 메서드의 this와 메서드 내부의 중첨 함수 또는 콜백 함수의 this가 불일치하는 문제를 해결하기 위해 사용됩니다.

지금까지의 내용을 정리해보면

함수 호출 방식this 바인딩
일반 함수 호출전역 객체
메서드 호출메서드를 호출한 객체
생성자 함수 호출생성자 함수가 생성할(미래) 인스턴스
apply , call , bindapply , call ,bind 메서드에 첫번째 인수로 전달할 객체

추가적으로 알게 되는 내용은 계속해서 업데이트 하겠습니다.
끝까지 읽어주셔서 감사합니다.😁

📌 참고

모던 자바스크립트 딥다이브

profile
끊임없이 노력하는 개발자

0개의 댓글