apply/call/ bind

devAnderson·2022년 1월 11일
0

TIL

목록 보기
23/103

베이스

객체 지향적 관점에서 특정 메서드가 상태를 변경시켜야 할 때에 그 상태를 보유한 객체 스스로를 언급해야 할 필요성이 있다.
또한 생성자 함수에서도 초기화되기 전 암묵적으로 생성되는 더미 객체를 지칭할 키워드가 필요한데 그때 쓰이는 것이 this다.

하지만 this의 특성상 함수의 호출시점에서 바인딩이 결정된다는 점에서 유동적으로 변하는 this를 고정할 필요성이 존재하게 된다.

이때 쓰이는 것이 apply/call/bind이다. 예를들어

function Construction () {
   this.name = "hello"
}

Construction.prototype.changeName = function(change){
   this.name = change;
}

const init = new Construction();

const button = document.querySelector('.button');
button.addEventListener('click', init.changeName);

위와 같은 코드가 대표적인 this의 변경에 따른 문제인데, addEventListener의 내부에서 init.changeName을 호출하는 대상은 더이상 init 객체가 아니게 되기 때문에 this가 undefined가 된다.

이것을 막기 위해 사용하는 방법은,

  • apply와 call을 이용해 this를 결정지으며 호출을 한다.
  • bind를 이용하여 메서드의 내부 this를 미리 바인딩한다.
  • 화살표 함수를 애초부터 메서드로 이용한다.

이다.

화살표 함수는 평가되는 시점의 상위 스코프에서 정의된 this를 자신의 This로 정하기 때문에 여기서 상위 스코프는 function Construction의 this가 되므로, 초기화될 암묵적 임시객체를 뜻하게 되는것과 같아진다.

만약 유동적으로, 그리고 개발자의 의도대로 this를 변경하고 싶다면 Function.prototype에서 제공하고 있는 apply/ call/ bind를 쓰면 된다.

apply / call

apply와 call은 this를 정의하면서 함수를 "호출한다"
둘의 차이는 인자로 전달하는 방식이 서로 다르다는 점만 있다

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

const targetThis = { a : 1 };

console.log(getThis.apply(targetThis, [1, 2, 3]);
console.log(getThis.call(targetThis, 1, 2, 3);

call은 첫째 인자를 제외한 나머지 후발 인자들을 모두 arguments로 할당하고,
apply 는 두번째 인자로 전달하는 배열을 arguments로 할당한다

bind

bind는 함수 내부에 존재하는 this를 주어진 bind의 인자로 바인딩한다.

const person = {
  name: "John",
  foo(callback){
   callback.bind(this);
  }
}

person.foo(function(){
  console.log(this.name);
} // John

위와 같이, 메서드에 bind를 해주면 person.foo에서 foo에 바인딩되는 this가 person이 되므로, callback함수의 실행 시 이 함수는 this인 person을 따르게 된다. (그냥 호출했다면 this는 window가 되어버린다)

bind 메서드 구현

  1. 바인드 메서드는 함수를 리턴한다(정확하게 말하면 클로져를)
  2. 리턴되는 함수는 bind 메서드에 인자로 전달된 값을 this로 사용하면서 호출되어야 한다.
function getThisBounding( ) {
   return this;
}

function.prototype.pseudoBind = function(obj){
   if(!obj) return this;

   return (...args) => this.apply(obj, args);  
}

위 내용에서 클로져가 참조하는 this는, 자신을 호출했던 함수 getThisBounding이 된다

profile
자라나라 프론트엔드 개발새싹!

0개의 댓글