프로그래밍 언어/JavaScript

[JavaScript] call, apply, bind

민졈 2022. 3. 7. 13:07

 

 

이번 시간에는 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를 사용해도 동일할 것이다.

 

 

 

 

 

 

 

 

 

 

 

* 본 포스팅은 코딩앙마님의 자바스크립트 중급 강좌를 기반으로 작성한 글입니다.