본문 바로가기
Programming

[Javascript] apply() vs call() vs bind() 차이

by 개발자 염상진 2022. 5. 21.

 

 

 

Javascript Function Method

 

appy, call, bind 메소드는 Function.prototype의 메소드다. 모든 함수는 prototype의 이 메소드들을 상속받는다. apply와 call 메소드는 기본적으로 this로 활용되는 객체와 인수 리스트를 전달받아 함수를 호출하는 본질적인 기능을 가지고 있다.

 

함수를 생성하고 [[Prototype]] 내부 슬롯을 확인해보면 이미 call, appy, bind 함수가 상속되어 있다.

 

 

첫번째 인자로는 해당 함수에 전달할 this 객체를 받는다.

두번째 인자로는 인수 리스트를 받는데, apply는 1개의 인수리스트를 받아 배열로 처리하고, call은 2개 이상의 인수리스트를 받아 쉼표로 구분된 배열을 처리한다.

function getThisBindings(){
  return this;
}

const thisArg = { temp : 1};
const args = [1,2,3,4,5]
const args1 = [1,2,3,4,5,6,7,8]

console.log(getThisBindings());

console.log(getThisBindings.apply(thisArg, args))
console.log(getThisBindings.call(thisArg, args, args1))
// apply 메소드
[Arguments] { '0': 1, '1': 2, '2': 3, '3': 4, '4': 5 }
{ temp: 1 }

// call 메소드
[Arguments] {
  '0': [ 1, 2, 3, 4, 5 ],
  '1': [
    1, 2, 3, 4,
    5, 6, 7, 8
  ]
}
{ temp: 1 }

 

 

call, apply 용도?

 

위에서 살펴본 것 처럼 apply와 call 메소드의 본질적인 용도는 함수 자체를 호출하는 것이다. 여기에  this로 연결될 객체를 임의로 연결해줄 수 있다. apply와 call을 대표적으로 사용하는 곳은 유사배열 객체에서 배열 메소드를 사용하는 경우다.

 

arrayLikeobj() 함수에 인수들을 전달해준다. 전달된 매개변수들은 객체 형태로 전달된다. 매개변수를 Array.prototype.slice() 메소드를 사용하면 TypeError를 반환한다.

function arrayLikeObj(){
  console.log(arguments);

  const arr = arguments.slice();

  console.log(arr);

  return arr;
}

arrayLikeObj("a","b","c");
TypeError: arguments.slice is not a function

 

유사 배열 객체(array like object)에서 배열 메소드를 사용하기 위해서 call 혹은 apply를 사용한다. 

function arrayLikeObj(){
  console.log(arguments);

  const arrCall = Array.prototype.slice.call(arguments);
  const arrApply = Array.prototype.slice.apply(arguments);

  console.log(arrCall);
  console.log(arrApply);

}

arrayLikeObj("a","b","c");

 

 

Function.prototype.bind()

bind 메소드는 apply와 call 처럼 함수를 호출하지 않는다. this로 사용할 객체만 전달하는 역할을 한다. bind 메소드를 사용하는 이유는 this와 메소드 내부의 중첩 함수 혹은 콜백 함수 사용시 this 객체가 의도한 대로 연결되지 않는 경우 임의로 this 객체를 연결하기 위해 사용한다.

 

아래 경우는 함수가 호출되는 시점에 따라 this 객체가 변경되는 것을 확인할 수 있다. 최종적으로 일반 함수로 호출되는 foo의 콜백함수로 전달된 익명함수의 this는 window 전역 객체를 가리키게 된다. 

const obj = {
  name : "About-Tech",
  foo(callback){
  
  // this는 foo 메소드를 호출한 obj 객체를 가리킨다.
  
    setTimeout(callback, 3000);
  }
}

obj.foo(function(){
  // 일반 함수로 호출되는 현재 시점에서 this는 전역 객체 window를 가리킨다.
  // Node.js에서 전역객체 window의 name은 undefined다.
  
  console.log(`[this] : ${this.name}`);
});
[this] : undefined

 

외부 함수 foo의 this객체와 콜백함수인 익명함수의 this객체를 일치시키기 위해서 bind() 메소드를 사용해서 this객체를 일치시켜준다.

const obj = {
  name : "About-Tech",
  foo(callback){
    setTimeout(callback.bind(this), 300);
  }
}

obj.foo(function(){
  console.log(`[this] : ${this.name}`);
});
[this] : About-Tech

 

 

 

this 바인딩

 

Javascript에서 this는 함수가 호출되는 방식에 따라 다르게 바인딩 된다. 따라서 this 객체 바인딩이 상이해지는 시점에서는 Function.prototype.call/apply/bind 메소드를 사용해서 매뉴얼하게 바인딩 작업을 해줘야 의도한 프로그래밍이 가능하다.

 

함수 호출 방식 this 바인딩
일반 함수 호출 this = 전역 객체
메소드 호출 this = 메소드를 호출한 객체
생성자 함수 호출 this = 생성자 함수가 생성할 예정인 인스턴스
Function.prototype.call/apply/bind에 의한 간접호출 this = Function.prototype.call/apply/bind에 첫번째 인수로 전달된 this 객체

 

 

 

 

Reference

 

 

 

 

[Javascript] 비동기 프로그래밍이란?

Javascript 비동기 프로그래밍이란? 비동기 프로그래밍을 이해하기 위해서 줄을 늘어선 대기 줄이 있다고 하자. 먼저 주문한 손님이 물건을 받을 때 까지 뒤의 손님들은 대기 줄에서 '기다릴 수 밖

about-tech.tistory.com

 

 

[Javascript] 명령형 vs 선언형 프로그래밍

Imperative Programming VS Declarative Programming 명령형 프로그래밍 VS 선언형 프로그래밍 리액트와 Javascript를 접하다보면 명령형 프로그래밍과 선언형 프로그래밍을 만나게 된다. 프로그래밍 하는 방식에

about-tech.tistory.com

 

 

[Javascript] Array Function some, sort, every 사용법

Javascript Array some 함수 some 함수는 배열의 요소 중 하나라도 참 값을 가지면 true를 반환하는 Javascript Array 함수다. 배열이 비어있는 경우나 조건식이 없는 경우의 초기 반환값은 false를 가진다. som.

about-tech.tistory.com

 

댓글