lighthouse.log

lighthouse.log

JavaScript 에서의 this (실행 컨텍스트)

2021-08-11

JavaScript에서의 this에 대해 정리한 내용입니다.

JavaScript의 this는 자유롭다

  • 자바스크립트에서 함수의 this 키워드는 다른 언어들과 비교하여 조금 다르게 동작한다
  • this 값은 런타임에 결정된다
  • 대부분의 경우 this 의 값은 함수의 호출하는 방법에 의해 결정된다 (이 부분이 포인트)
  • this는 현재 실행되는 코드의 실행 컨텍스트를 가리킨다
컨택스트란?
- JS는 스크립트 언어로 인터프리터에 의해
  줄 단위로 읽혀서 해석되어 실행된다
- 인터프리터에 의해 현재 실행되는 자바스크립트의 환경을
  "실행 컨텍스트" 라고 한다
- 자바스크립트 내부에서 이러한 실행 컨텍스트를 스택으로 관리하며
  실행되는 시점에 자주 변경되는 실행 컨택스트를 this가 가리킨다
  • 즉, 누가 호출했느냐에따라 this가 바뀌게 된다

    • 동일한 함수라도 다른 객체에서 호출했다면 ‘this’가 참조하는 값이 달라진다는 것을 의미한다
    • 실행하는 동안 할당에 의해 설정될 수 없고 함수가 호출될 때마다 다를 수 있다

function 에서의 this

const someone = {
  name: 'lighthouse',
  whoAmI: function () {
    console.log(this);
  }
};

someone.whoAmI();
// someone 객체가 출력 {name: "lighthouse", whoAmI: ƒ}

const myWhoAmI = someone.whoAmI;
myWhoAmI(); // window 객체가 출력

// btn이 호출하였으므로 button 엘리먼트가 출력
const btn = document.getElementById('btn');
btn.addEventListener('click', someone.whoAmI); // button 엘리먼트가 출력
btn.addEventListener('click', myWhoAmI); // button 엘리먼트가 출력

this 바인딩

const bindedWhoAmI = myWhoAmI.bind(someone);

// 모두 someone 객체가 출력
btn.addEventListener('click', someone.whoAmI);
bindedWhoAmI();

Function.prototype 객체의 메서드인 call, apply, bind 를 통해 명시적으로 this를 바인딩해 줄 수도 있다.

자유로운 this가 만드는 결과

  • 다른 언어를 사용하다 자바스크립트로 넘어온 개발자는 this를 혼동하기 쉽다.

    • this는 항상 메서드가 정의된 객체를 참조할 것이라고 착각하기 때문이다.
    • 이런 개념을 bound this 라고 한다.
  • 자바스크립트에서 this는 런타임에 결정된다.

    • 메서드가 어디서 정의되었는지에 상관없이 this는 ‘점 앞의’ 객체가 무엇인가에 따라 ‘자유롭게’ 결정된다
  • 이렇게 this가 런타임에 결정되면 좋은 점도 있고 나쁜 점도 있다.

    • 함수(메서드)를 하나만 만들어 여러 객체에서 재사용할 수 있다는 것은 장점이지만
    • 이런 유연함이 실수로 이어질 수 있다는 것은 단점이다.
  • 자바스크립트가 this를 다루는 방식이 좋은지, 나쁜지는 우리가 판단할 문제가 아니다.

    • 개발자는 this의 동작 방식을 충분히 이해하고 장점을 취하면서 실수를 피하는 것에 집중할 필요가 있다.

this가 없는 화살표 함수

  • 화살표 함수가 나오기 전까지는 모든 새로운 함수는 어떻게 그 함수가 호출되는지에 따라 자신의 this값을 정의했다

    • 해당 함수가 생성자인 경우에는 새로운 객체
    • 엄격 모드 함수 호출에서는 undefiend
  • 화살표 함수는 일반 함수와는 달리 ‘고유한’ this를 가지지 않는다.

    • 화살표 함수에서 this를 참조하면, 화살표 함수가 아닌 ‘평범한’ 외부 함수에서 this 값을 가져온다
    • 아래 예시에서 함수 arrow() 의 this는 외부 함수 user.sayHi() 의 this가 된다
let user = {
  firstName: 'lighthouse',
  sayHi() {
    let arrow = () => alert(this.firstName);
    arrow();
  }
};

user.sayHi(); // lighthouse
  • 단순히 코드량이 줄어드는 것 외에 별개의 this가 만들어지는 건 원하지 않고
  • 외부 컨텍스트에 있는 this를 이용하고 싶은 경우 화살표 함수가 유용하다

정리

  • 자바스크립트에서 함수의 this 키워드는 다른 언어들과 비교하여 조금 다르게 동작한다

    • this 값은 런타임에 결정된다
    • 대부분의 경우 this 의 값은 함수의 호출하는 방법에 의해 결정된다 (이 부분이 포인트)
    • 즉, 누가 호출했느냐에따라 this가 바뀐다
  • 함수의 this 값이 함수가 어떻게 호출되었는지 개의치 않고 설정할 수 있는 bind 메소드이다

    • 호출된 값과 무관하게 this를 묶어버릴 수 있는 것이 바로 bind 메소드
  • 다른 언어를 사용하다 자바스크립트로 넘어온 개발자는 this를 혼동하기 쉽다.

    • this는 항상 메서드가 정의된 객체를 참조할 것이라고 착각하기 때문이다.
    • 이런 개념을 ‘bound this’라고 함.
    • 이렇게 this가 런타임에 결정되면 좋은 점도 있고 나쁜 점도 있다.
    • 함수(메서드)를 하나만 만들어 여러 객체에서 재사용할 수 있다는 것은 장점이지만
    • 이런 유연함이 실수로 이어질 수 있다는 것은 단점이다.
    • 개발자는 this의 동작 방식을 충분히 이해하고 장점을 취하면서 실수를 피하는 것에 집중할 필요가 있다.
  • 화살표 함수는 일반 함수와는 달리 ‘고유한’ this를 가지지 않는다.

    • 화살표 함수에서 this를 참조하면, 화살표 함수가 아닌 ‘평범한’ 외부 함수에서 this 값을 가져온다

참고 문서