자바 스크립트는 기본적으로 함수가 객체입니다.
함수에 객체를 바인딩 하는 방법에는 call과 apply 그리고 bind가 있습니다.
세가지 모두 목적은 비슷하지만 사용방법은 전혀 다릅니다.
예제를 보면서 세가지 방법을 비교해보도록 하겠습니다.
예제는 Learning Javascript 의 예제를 조금 변형해서 사용하겠습니다.

call

const bruce = { name: "Bruce" };
const madeline = { name: "Madeline" };

function greet() {
    return `Hello, I'm ${this.name}!`;
}
greet();
greet.call(bruce);	
greet.call(madeline);	

다음과 같은 예제가 있습니다. bruce와 madeline이라는 객체입니다. greet 이라는 함수 객체가 있습니다.

3가지는 모두 객체지만 표현 방법이 다릅니다. bruce = { name: "Bruce" }; 이런 형태의 객체의 객체 표현 방법을 객체 리터럴 (object literal)이라고 합니다.

함수 실행은 greet(); 으로 할수 있습니다. 이때 this 의 name 은 정의되지 않은 undefined 상태입니다.

greet.call(bruce); call 메서드로 bruce 객체를 전달하면 this 가 bruce로 바인딩 되고 name은 ‘Bruce’로 변경 됩니다.

Hello, I’m Bruce!

madeline을 전달한다면 ‘Madeline’으로 변경되게 되겠죠.

function update(birthYear, occupation) {
    this.birthYear = birthYear;
    this.occupation = occupation;
}

update.call(bruce, 1949, 'singer');	// {"name":"Bruce","birthYear":1949,"occupation":"singer"}
update.call(madeline, 1942, 'actress'); // {"name":"Madeline","birthYear":1942,"occupation":"actress"}

또 다른 함수인 update를 만들어 볼께요.

이번에는 객체 외에 birthYear, occupation 인자도 넘겨보겠습니다.

update 객체(함수)의 파라미터 객체, 인자1, 인자2 가 설정 됩니다.

update.call(bruce, 1949, 'singer');

bruce의 birthYear 에는 1949, occupation 가 ‘singer’로 설정됩니다.

{"name":"Bruce","birthYear":1949,"occupation":"singer"}

madeline 도 마찬가지로 설정됩니다.

apply

var people  = [bruce, madeline];
function add(first, second) {
    first.name;	
    second.name;
}
add.apply(null, people);

apply는 call 과 같은 기능을 하지만 apply는 인자로 배열을 넘깁니다.

add 함수에 객체 타겟을 정하지 않고 people 배열을 넘기게 되면 인자로 전달된 people 배열이 first, second에 바인딩 됩니다. 결과적으로 add 함수 내의 first 에는 bruce 객체 second에는 madeline객체가 바인딩됩니다.

const arr = [2, 3, -5, 15, 7];
Math.min.apply(null, arr);
Math.max.apply(null, arr);

참고로 apply 는 Math의 min, max 메서드에도 활용할 수 있습니다. 간단하게 배열의 최소값과 최대값을 리턴합니다.

bind

const updateBruce = update.bind(bruce)
updateBruce(1904, "actor");		// { name: 'Bruce', birthYear: 1904, occupation: 'actor' }
updateBruce(madeline, 1274, "king"); 	// { name: 'Bruce', birthYear: { name: 'Madeline'}, occupation: 1274 }

const updateBruce1949 = update.bind(bruce, 1949);
updateBruce1949("singer, songwriter"); // { name: 'Bruce', birthYear: 1949,  occupation: 'singer, songwriter' }

const updateBruce = update.bind(bruce) update 함수에 bruce를 바인딩 해서 updateBruce 에 담았습니다. bruce 의 { name: 'Bruce', birthYear: 1904, occupation: 'actor' } 로 데이터가 설정됩니다.

updateBruce(madeline, 1274, "king"); 이렇게 updateBruce를 호출 한다면 결과가 어떻게 될까요.

bruce객체는 { birthYear: { name: 'Madeline' }, occupation: 1274 } 로 설정됩니다.

생각하신데로 birthYear, occupation 에 각각 madeline과 1274로 설정되고 “king”의 경우는 인자변수로 받지 못한 상태입니다. 접근 하고 싶다면 arguments 유사 배열을 활용하셔야 합니다.

const updateBruce1949 = update.bind(bruce, 1949);

객체와 인자 1949로 바인딩을 하다면 어떻게 될까요. 이렇게 하면 update 첫번째 인자가 1949로 고정된 상태가 됩니다.

updateBruce1949("singer, songwriter"); 그래서 다음과 같이 “singer, songwriter” 인자 하나를 넘기게 되도 { name: 'Bruce', birthYear: 1949, occupation: 'singer, songwriter' } 로 occupation 만 설정이 됩니다.

항상 같은 매개변수를 받는 함수를 만들 수 있습니다!!

Reference

  1. Learning Javascript