자바스크립트에서의 this와 call, apply, bind

dahyeon·2023년 1월 2일
0

자바스크립트

목록 보기
4/7
post-thumbnail
post-custom-banner

자바스크립트 실행 문맥(링크)를 이해한 후 읽으시길 추천드립니다!


this

실행 문맥의 디스 바인딩 컴포넌트

자바스크립트는 실행 가능한 코드(예를 들어 함수)를 만나면 그 코드를 평가해서 실행 문맥을 만드는데, 실행 문맥에는 실행에 필요한 모든 정보가 담겨 있다. 실행 문맥을 구성하는 컴포넌트에는 렉시컬 환경 컴포넌트디스 바인딩 컴포넌트가 있다. 디스 바인딩 컴포넌트는 그 함수를 호출한 객체의 참조가 저장되는 곳으로, 이것이 가리키는 값이 해당 실행 문맥의 this가 된다.

this 값은 어떻게 결정되는가?

this 값은 ‘함수가 호출되었을 때 그 함수가 속해 있던 객체의 참조’이다.

→ this의 값은 함수가 호출되어 실행되는 시점에 결정된다.

아래의 예시에서 출력값은 어떻게 될까?

let user = {
  firstName: "John",
  sayHi() {
    alert(`Hello, ${this.firstName}!`);
  }
};

setTimeout(user.sayHi, 1000);

getName 함수 내부에서 this.firstName을 출력하는데, 여기서 thisuser 객체의 메소드로 호출되었으므로 user 객체가 될 것만 같다.

그러나 결과값은 undefined가 나온다. (!!)

그 이유는 user.sayHiuser 객체에서 분리되어 전달되고, setTimeout에서 인수로 전달받은 함수를 호출할 때, this에 window를 할당하기 때문이다.

→ 자바스크립트 함수는 특정 객체에 묶여 있지 않다.

다양한 상황에서 this가 가리키는 값

  • 최상위 레벨 코드의 this
    전역 객체(window)를 가리킨다.
  • 이벤트 처리기 안에 있는 this
    이벤트가 발생한 요소 객체를 가리킨다.
  • 생성자 함수 및 생성자의 prototype 메서드 안에 있는 this
    그 생성자로 생성한 객체를 가리킨다.
  • 직접 호출한 함수 안에 있는 this
    함수를 최상위 레벨에서 호출하면 전역 객체를 가리키고, 함수 앞에 어떤 객체를 붙여서 호출하면 그 객체를 가리킨다.
  • 화살표 함수의 this
    화살표 함수의 this 값은 함수를 정의할 때 결정된다. 화살표 함수 바깥의 this 값이 화살표 함수의 this 값이 된다.
    ❗ 화살표 함수는 아래의 call, apply를 사용하여 this를 바꾸어 호출해도 this값이 바뀌지 않는다.

call, apply, bind

앞에서 언급한 예시를 다시 한 번 살펴보자. 해당 예시에서는 thisuser 객체를 가리키길 기대했지만 다른 객체(예시에서는 전역 객체)를 가리키고 있다.

원하는 대로 ‘John’이 출력되게끔 하는 방법에는 두 가지가 있는데,

첫 번째는 실행 문맥의 외부 렉시컬 환경 참조를 활용하는 것이다.

다음의 코드를 보자.

let user = {
  firstName: "John",
  sayHi() {
    alert(`Hello, ${this.firstName}!`);
  }
};

setTimeout(() => {
  user.sayHi(); // Hello, John!
}, 1000);

이 코드에서는 setTimeout에서 인수로 전달받은 함수를 호출할 때 외부 렉시컬 환경에서 user을 받아서 보통 때처럼 메서드를 호출하게 된다.

하지만 이 경우 setTimeout이 트리거 되기 전에(1초가 지나기 전에) user가 변경되면, 변경된 객체의 메서드를 호출하게 된다는 문제점이 있다.

두 번째 방법은 this 객체를 직접 설정해주는 것이다.

앞으로 설명할 call, apply, bind는 모두 Function 객체의 메서드로 this와 인수를 설정할 수 있게 해준다.

bind

bind() 메서드는 선택한 this와 인수를 적용한 새로운 함수를 반환한다.

  • syntax
    fn.bind(thisArg[, arg1[, arg2[, ...]]])
  • call, apply와의 차이점 bind()call()apply()와는 달리 함수를 즉시 실행하지 않고, thisArg에 넣은 this 값 및 arguments로 넣어준 인수(arg1, arg2…)를 갖는 함수를 리턴한다.

앞서 언급한 예시에 bind()를 적용해보면 다음과 같다.

let user = {
  firstName: "John",
  sayHi() {
    alert(`Hello, ${this.firstName}!`);
  }
};

let sayHi = user.sayHi.bind(user);

setTimeout(sayHi, 1000); // Hello, John!

call

call() 메서드는 선택한 this와 인수를 사용하여 함수를 호출한다. 인수는 쉼표로 구분한 값이다.

  • syntax
    fn.call(thisObj, args1, args2, ...)

apply

apply() 메서드는 선택한 this와 인수를 사용하여 함수를 호출한다. 인수는 배열 객체다.

  • syntax
    func.apply(thisObj, argumentsArray);

참고 자료

책 <모던 자바스크립트 입문>, 이소 히로시 지음
함수 바인딩
How to Use the Call, Apply, and Bind Functions in JavaScript - with Code Examples

profile
https://github.com/dahyeon405
post-custom-banner

0개의 댓글