this

se-een·2022년 12월 9일
0
post-thumbnail

이 글은 '이웅모'님의 '모던 자바스크립트 Deep Dive' 책을 통해 공부한 내용을 정리한 글입니다. 저작권 보호를 위해 책의 내용은 요약되었습니다.

this

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

자바스크립트에서 this는 상황에 따라 달리 바인딩된다. 즉, 함수 호출 방식에 의해 동적 바인딩된다. 이 부분이 처음 JS에서 this를 사용할 때 어려운 부분인 것 같다. C++ 또는 Java 같은 클래스 기반 언어에서는 this는 언제나 클래스가 생성한 인스턴스를 가리키기 때문에 헷갈리기 쉽다.

요약

  • 일반 함수에서의 this, 내부 함수에서의 this : 전역 객체(window, global)
  • 메서드에서의 this : 메서드를 호출한 객체
  • 생성자 함수에서의 this : 생성자 함수가 생성할 인스턴스
  • 화살표 함수에서의 this : 상위 스코프의 this
  • 이벤트 리스너에서의 this : 이벤트를 발생시킨 객체

함수 호출 방식과 this 바인딩

함수 호출 방식은 다음과 같이 다양하다. 함수 호출 방식에 따른 this 바인딩을 알아보도록 하겠다.

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

일반 함수 호출

기본적으로 this에는 전역 객체(Global Object)가 바인딩된다.

function a() {
  console.log("a this : ", this); // a this : window
  function b() {
    console.log("b this : ", this); // b this : window
  }
  b();
}
a();
const obj = {
  foo() {
    function a() {
      console.log("obj a this : ", this); // obj a this : window
    }
    a();
  }
};

obj.foo();

이처럼 일반함수에서의 this아무런 의미가 없다. 만약 strict mode가 적용된다면 함수 내부의 this에는 undefined가 바인딩 된다.

function a() {
  'use strict';
  console.log("a this : ", this); // a this : undefined
}
a();

중첩함수, 콜백함수이라 할지라도 일반함수로 호출된다면 this에는 전역 객체가 바인딩된다. 따라서 apply call bind 함수를 통해 this를 바인딩하거나 화살표 함수를 활용한다.

메서드 호출

메서드 내부의 this에는 메서드를 호출한 객체가 바인딩된다.

const obj = {
  name: 'kim',
  getName() {
    return this.name;
  }
};
const anotherObj = {
  name: 'Lim',
};

console.log(obj.getName()); // kim

anotherObj.getName = obj.getName;

console.log(anotherObj.getName()); // Lim

메서드 내부의 this는 메서드를 소유한 객체가 아닌 메서드를 호출한 객체에 바인딩된다는 것에 주의한다.

생성자 함수 호출

생성자 함수 내부의 this에는 생성자 함수가 앞으로 생성할 인스턴스가 바인딩된다.

function Foo(number) {
  this.number = number;
  this.square = function() {
    return this.number * this.number;
  }
}

const a = new Foo(5);
console.log(a.square()); // 25

apply/call/bind 메서드에 의한 간접 호출

applycall 메서드의 본질적인 기능은 함수를 호출하는 것이다. 함수를 호출하면서 첫 번째 인수로 전달한 특정 객체를 호출한 함수의 this에 바인딩한다. 이 둘의 차이점은 함수 인수를 전달하는 방법에 있을 뿐, 동작 방식은 동일하다.

function getThis() {
  console.log(arguments);
  return this.name;
}

const obj = { name : 'kim' };

console.log(getThis.apply(obj, [1,2,3]));
// Arguments(3) [1, 2, 3, callee: ƒ, Symbol(Symbol.iterator): ƒ]
// kim

console.log(getThis.call(obj, 1, 2, 3,));
// Arguments(3) [1, 2, 3, callee: ƒ, Symbol(Symbol.iterator): ƒ]
// kim

bind 메서드는 applycall 메서드와 달리 함수를 호출하지 않는다. 첫 번째 인수로 전달한 값으로 this 바인딩이 교체된 함수를 새롭게 생성해 반환한다. bind 메서드는 화살표 함수가 나오기 전까지 메서드의 this와 중첩 또는 콜백 함수의 this가 불일치 하는 문제를 해결하는데 유용하게 사용되었다.

function getThis() {
  return this.name;
}

const obj = { name : 'kim' };

console.log(getThis.bind(obj)()); // kim

화살표 함수와 this 바인딩

화살표 함수(Arrow Function)은 일반적인 동적 this 바인딩과는 다르게 정적 this 바인딩을 가진다. 즉 Lexical this를 가진다. 화살표 함수의 this는 언제나 상위 스코프의 this를 가리킨다. 그래서 화살표 함수는 this가 없다고도 표현한다.

const obj = {
  name : 'kim',
  
  whatIsYourName () {
    const arrow = () => this.name;
    console.log(arrow()); // kim
    
    const nomal = function() {
      return this.name;
    }
    console.log(nomal()); // undefined
  }
};

obj.whatIsYourName(); 

이벤트 리스너와 this 바인딩

이벤트 리스너에서 this는 이벤트를 발생시킨 객체에 바인딩된다.

const button = document.querySelector('#button');

button.onclick = function () {
  console.log(this); // button
};
profile
woowacourse 5th FE

0개의 댓글