[JavaScript] call, apply, bind
이번 시간에는 call, apply, bind에 대해 배워볼 것이다.
자바스크립트에서는 일반적인 방법 외에도 함수를 어디서 어떻게 호출했느냐에 관계 없이 this를 지정할 수 있다.
1. call
: call 메소드는 모든 함수에서 사용할 수 있으며, this를 특정값으로 지정할 수 있다.
mike와 tom이라는 객체가 있고 showThisTime이라는 함수가 있을 때 showThisTime 함수를 호출한다면 어떨까?
const mike = {
name: "Mike",
};
const tom = {
name: "Tom",
};
function showThisName () {
console.log(this.name);
}
showThisName();
|
아마 아무것도 나타나지 않을 것이다.
showThisName에서 나타내고 있는 this는 window이기 때문이다.
window.name은 빈 문자열이기 때문에 아무것도 나타나지 않는다.
그렇다면 call 함수를 사용한다면 어떨까?
showThisName.call(mike);
|
함수를 호출하면서 call을 사용하고, this로 객체를 넘겨주게 된다면
해당 함수가 주어진 객체의 메소드인 것처럼 사용할 수 있다.
call 의 첫번째 매개 변수는 함수에 있는 this의 값이 되는 것이고 매개 변수가 더 있다면 그 매개 변수를 사용하는 함수로 전달된다.
update 함수를 만들었다.
이 update 함수는 생년과 직업을 받아서 객체의 정보를 새로운 내용으로 update 해준다.
function update(birthYear, occupation) {
this.birthYear = birthYear;
this.occupation = occupation;
};
|
mike 객체에 생년과 직업을 넣어주고 콘솔에 mike 객체를 찍어본다면 아래와 같은 결과가 나온다.
첫번째 매개변수는 함수의 this에서 사용 할 값이고,
두번째와 세번째 매개 변수는 update 함수에서 사용할 매개 변수를 순서대로 적은 것이다.
update.call(mike, 1996, 'chef');
console.log(mike); // {name: 'Mike', birthYear: 1996, occupation: 'chef'}
|
mike 객체가 가지고 있던 이름에 birthYear 와 occupation이 추가된 것을 볼 수 있다.
2. apply
: apply는 함수 매개변수를 처리하는 방법을 제외하면 call과 완전히 같다.
call은 일반적인 함수와 마찬가지로 매개변수를 직접 받지만, apply는 매개변수를 배열로 받는다.
update.apply(mike, [1996, 'chef']);
console.log(mike); // {name: 'Mike', birthYear: 1996, occupation: 'chef '}
|
사용 방법은 call과 똑같지만 전달하는 매개 변수를 배열로 묶어줘야 한다.
최소값과 최대값을 구하는 함수가 있을 때 아래처럼 사용하면 문제 없이 작동하지만,
const minNum = Math.min(3, 10, 1, 4, 5);
const maxNum = Math.max(2, 10, 1 ,4, 5);
console.log(minNum); // 1
console.log(maxNum); // 10
|
매개변수들을 배열로 묶는다면 오류가 발생한다.
const minNum = Math.min([3, 10, 1, 4, 5]);
console.log(minNum); // NaN
console.log(maxNum); // 10
|
앞서 spread( ) 함수를 배웠기 때문에 아래 배열 nums를 spread( ) 함수를 사용하여 minNum과 maxNum에 넣어보자.
const nums = [3, 10, 1, 4, 5];
const minNum = Math.min(...nums);
const maxNum = Math.max(...nums);
console.log(minNum); // 1
console.log(maxNum); // 10
|
위처럼 오류 없이 잘 나오는 것을 확인할 수 있다.
그렇다면 이 nums를 apply를 사용한다면 어떻게 해줘야 할까?
apply는 두번째 매개변수로 배열을 전달하면 그 배열을 차례대로 인수로 사용한다.
첫번째 인수는 this에 들어가는 값이지만 minNum이나 maxNum에는 this로 사용할 무언가가 없기 때문에 null 같이 아무 값이나 넣어줘도 된다.
const minNum = Math.min.apply(null, nums);
const maxNum = Math.max.apply(null, nums);
console.log(minNum); // 1
console.log(maxNum); // 10
|
위의 두 줄의 코드는 아래와 같은 모습이 되는 것이다.
const minNum = Math.min.apply(null, nums);
// = Math.min.applu(null, [3, 10, 1, 4, 5])
const maxNum = Math.max.apply(null, nums);
// = Math.max.applu(null, [3, 10, 1, 4, 5])
|
call 함수를 사용한다면 이렇게 된다.
const maxNum = Math.max.call(null, ...nums);
|
3. bind
: 함수의 this 값을 영구적으로 바꿀 수 있다.
call을 설명하면서 사용했던 update 함수를 가지고 새로운 함수인 updateJohn을 만든다면,
여기에서 this의 birthYear과 occupation은 영구적으로 1770과 singer가 되는 것이다.
const john = {
name: 'john',
};
function update(birthYear, occupation) {
this.birthYear = birthYear;
this.occupation = occupation;
};
const updateJohn = update.bind(john);
updateJohn(1770, "singer");
|
종합 예제를 살펴보자
const user = {
name: 'Tom',
showName: function () {
console.log(`hello ${this.name}`);
},
};
user.showName(); // hello, Tom
|
user라는 객체가 있고 이 user의 showName 함수를 호출한다면
this에 Tom이 들어가서 hello, Tom이 반환되는 것을 볼 수 있다.
fn이라는 변수를 만들고 선언한다면 아무것도 나오지 않는다.
let fn = user.showName();
fn( ); // hello,
|
fn을 할당할 때 this를 잃어버린 것이다.
메소드는 . 앞에 있는 것이 this인데 fn만 사용해주니 this가 없는 것이나 마찬가지가 된 것이다.
call을 사용해서 this에 사용할 값으로 user를 넘겨주면
fn.call(user); // hello, Tom
fn.apply(user); // hello, Tom
|
this에 해당하는 Tom이 잘 나온다.
apply를 사용해도 동일할 것이다.
* 본 포스팅은 코딩앙마님의 자바스크립트 중급 강좌를 기반으로 작성한 글입니다.