본문 바로가기
Javascript

JavaScript의 Call, Apply, Bind

by ttum 2020. 6. 24.

☝ 우선 call, apply, bind를 위해서는 this에 대한 이해가 선행되어야 함. ☝

일반적으로 JavaScript의 this는 해당 함수를 호출한 객체를 의미한다. (화살표함수에서 제외하고!)

 

이게 무슨말이야?? 함수를 호출한 객체? 🤦‍♀️...

const toy = {
    name: 'forky',
    favorite: 'trash',
    introduce(){
        console.log(`My name is ${this.name}, I like ${this.favorite}`);
    }
}

toy.introduce(); // My name is forky, I like trash

여기서 introduce를 호출한 주체는 누구일까? ⇒ 바로 toy!!!가 된다.

이건 어렵지 않게 이해할 수 있다.

 

그렇다면 조금 더 깊이 들어가서, whoIsThis 함수에서 this를 출력하면 어떤게 나올까?

이번에도 역시 toy 객체일까?

const toy = {
    name: 'forky',
    favorite: 'trash',
    introduce(){
        console.log(`My name is ${this.name}, I like ${this.favorite}`);

        const whoIsThis = function(){
            console.log(this)
        }
        whoIsThis();
    },

}

toy.introduce()

이번에는 window객체가 나오는걸 확인할 수 있다. 왜 그런걸까?

⇒ 간단하다. whoIsThis는 toy가 호출하지 않았으니까! 쉽게 말해서 toy.whoIsThis()가 아니었으니까!

 

참고로 JavaScript 전역에서 사용하는 this는 window객체를 가리킨다.
크롬 콘솔창에 this 라고만 쳐도 Window 객체가 뜨는 것을 확인할 수 있다.
🚩 주의할 점은 "use strict" 모드에서는 this에 window 객체를 넘기지 않기 때문에 undefined가 된다.

 

그런데... 나는 저런 결과를 원한 것이 아니었다. 😂

this라고 쳐도 toy 객체라고 알려줬으면 좋겠다. 이럴 때 사용할 수 있는 방법 중 하나가 Call, Apply, Bind 함수이다. 함수 호출의 주체를 toy 객체라고 명시적으로 알려주는 것이다.

# Call

일반적으로 함수를 호출할 때는 call이 생략되어 있다고 봐도 무방하다.

const sum = function(a, b) { console.log(a+b); }
sum(1, 2);
sum.call(null, 3, 4);

그래서 2번째 줄과 3번째 줄 모두 동일하게 sum 함수를 호출하는 것이다.

 

🤷‍♀️ 그럼 저 앞에 null은 뭐야??

이게 바로 조금 전에 말한 객체를 바인딩해주는 위치인 것이다.

📢 함수야, 이제 너를 호출하는 주체는 toy 란다. 알겠니???

이렇게 직접 알려주는 것이다. 그럼 아까 위의 예제를 call 함수를 사용해 변경해보자.

 

이번에는 whoIsThis를 출력해도 toy 객체가 나오게 했으면 한다.

const toy = {
    name: 'forky',
    favorite: 'trash',
    introduce(){
        console.log(`My name is ${this.name}, I like ${this.favorite}`);

        const whoIsThis = function(){
            console.log(this)
        }
        whoIsThis.call(this);
    }
}

toy.introduce()

whoIsThis.call(this); 이 부분을 보면 call 함수를 이용한 것을 확인할 수 있다.

 

introduce의 호출 주체는 toy였고, whoIsThis의 호출 주체는 window객체였다.

그러나 whoIsThis를 호출하면서 이제부터 너의 this는 toy가 될거야(introduce의 this는 toy였으니까)하고 알려준 셈이 된 것이다.

 

그래서 call은 this를 설정해주는 역할을 한다고 보면 꽤 간단하게 이해가 간다 😊

# Apply

그럼 apply 함수는 무엇인가?

이제 위의 toy 예제에서 좀 벗어나보자.😂 어쨋든 call, apply, bind 모두 this를 지정해주는 역할을 한다는 것은 같다.

 

심지어 apply는 call이랑 완전 비슷하다. 둘다 this를 설정해주면서 함수를 실제로 호출한다.(마지막으로 다룰 bind는 this를 바인딩만해주고 호출은 하지 않는다.)

const sum = function(a, b) { console.log(a+b); };
sum.call(null, 3, 4);
sum.apply(null, [3, 4]);

다시 이 예제를 가져왔다. 여기서 객체가 들어갈 자리에 null이 있던 이유는 단지 sum 함수를 호출할때는 객체가 중요하지 않으니까! 아주 단순하다😀 (단순히 해당 함수에서는 함수 호출 주체를 사용할 필요가 없어서 null이라고 해놓은 거였다.)

 

위 예제를 보면 call과 apply가 거의 똑같은 방식으로 호출→출력되는 것을 확인할 수 있다.

차이점은? ⇒ call은 매개변수들을 쭉 적는 방식이고 apply는 array형식으로 적는다.

정말 그 차이 뿐이다. 일반적으로는 call을 많이 쓰고, apply는 특정 경우에 많이 사용한다.

바로 매개변수의 길이가 가변할때‼ 그래서 매개변수들이 배열형식으로 있으면 좋을 때 사용한다.

# Bind

bind를 위해서 마지막으로 toy 예제를 한번만 더 사용해보자 😂

const toy = {
    name: 'forky',
    favorite: 'trash',
    introduce(){
        console.log(`My name is ${this.name}, I like ${this.favorite}`);

        const whoIsThis = function(){
            console.log(this)

        }.bind(this);
        whoIsThis();
    },

}

toy.introduce();

이번에는 whoIsThis함수 끝에 this를 바인드해줬다.

이렇게 함수를 호출할 주체인 객체를 직접 바인딩해주는 방법도 있다.

Call에 대해 제대로 이해했다면 사실 bind는 쉽게 이해할 수 있다 ☝ (아마..?)

 

다만 차이점은,

👉 Call, Apply는 객체를 bind하고 바로 호출하는 것이고, Bind는 bind만 하는 것(호출은 안함)이다 ‼