JS 시리즈 - 콜백 함수

개발자 하디·2022년 2월 8일
1

JAVASCRIPT시리즈

목록 보기
7/7

🙈 INTRO

다들 자바스크립트를 공부하시거나 개발하시면서
'콜백 함수'에 대해서 많이 들어보시거나 사용해보셨을겁니다.
이번 주제는 콜백함수에 대해서 알아보도록 하겠습니다.

  • 콜백함수?
  • 실행시점
  • 매개변수
  • this
  • 콜백함수는 함수다.
  • 콜백함수 내부에 this 바인딩

이 순서 대로 알아보도록 하겠습니다.

1. 콜백함수?

콜백함수는 다른 함수 또는 메서드에게 인자로 넘겨줌으로써 자기의 제어권도 함께 위임한 함수라고 생각하시면 됩니다.

즉, 자기의 제어권은 이제 다른 함수 나 메서드에게 넘어간것입니다.

😀 제어권 위임에는 3가지가 있습니다.
1. 실행시점
2. 매개변수
3. this

하나하나씩 알아보겠습니다.

2. 실행시점

😊 코드 먼저 보며 알아봅시다.

let count = 0;
const 콜백함수 = function(){
    console.log('나는 콜백함수다.');
    if(++count > 3) clearInterval(timer);
};

const timer = setInterval(콜백함수, 1000); // (1)

(1) setInterval은 첫번째 인자로 callBack 함수를 받고 두번째 인자로 밀리세컨드 단위의 시간을 받아 지정한 시간만큼 계속 콜백함수를 실행하는 함수입니다. 콜백함수setInterval에 콜백함수를 넘어가 setInterval이 콜백함수의 실행시점 제어권을 정합니다. 그래서 setInterval에서 지정한 시간만큼 계속 반복적으로 실행이 됩니다.

이처럼 콜백 함수의 제어권을 넘겨받은 코드는 콜백 함수 호출 시점에 대한 제어권을 가집니다.

3. 매개변수

😊 배열의 모든 요소들을 처음부터 끝까지 하나씩 꺼내어 콜백함수를 반복 호출하고, 콜백 함수의 실행 결과들을 모아 새로운 배열을 만드는 map 메서드를 통해 알아봅시다.

우선 map메서드는 이렇게 정의 되어있습니다.

Array.prototype.map(callback[, thisArg])
callback: function(currentValue, index, array)

  • map메서드는 첫 번째 인자로 callback 함수를 받는다.
  • 두번째 인자는 콜백함수 내부에서 this로 인식할 주체를 넣는다. (생략가능, 생략할시 this는 전역객체 참조)
  • 콜백함수에는
    • currentValue : 현재 배열 요소
    • index : 현재 인덱스
    • array : map 메서드를 호출하는 주체인 배열

이렇게 콜백함수의 3가지의 매개변수를 지정을 해놓았다.

const 콜백함수 = function(v, i, arr){ // (1)
    console.log(v,i);
    if(arr.length - 1 === i) console.log(this);
    return v+i;
}

const new배열 = [1,2,3].map(콜백함수, {name:'coder_h'}); // (2)

console.log(new배열); // (3)

(1) map메서드에서 콜백함수에 지정한 매개변수를 받아서 출력하고 map메서드를 호출하는 주체인 배열의 마지막 인덱스요소를 건드릴때 콜백함수의 this를 출력하며 새로운 배열의 요소로 배열의 첫번째 요소와 인덱스를 더한 값을 차례대로 리턴하는 콜백함수를 만들었다.

(2) map메서드를 이용하여 첫번째 인자로 콜백함수와 두번째 인자로 콜백함수 내부에서 this로 인식할 주체를 넘겨준다.

(3)
1 0
2 1
3 2
{ name: 'coder_h' }
[ 1, 3,
5 ]

결과는 보시다시피 출력이 된다.

😍즉, map 메서드를 이용하여 원하는 배열을 얻기 위해서는 map 메서드가 정의된 규칙에 따라 함수를 작성해야 합니다.

  • map 메서드에 정의된 규칙에는 콜백 함수의 인자로 넘어올 값들 및 그 순서도 포함돼 있습니다.
  • 이처럼 콜백 함수의 제어권을 넘겨받은 코드는 콜백 함수를 호출할 때 인자에 어떤 값들을 어떤 순서로 넘길 것인지에 대한 제어권을 가집니다.

3. this

😉 콜백함수도 함수이기 때문에 기본적으로 this는 전역객체를 참조합니다.

그러나, 제어권을 넘겨받을 코드에서 콜백 함수에 별도로 this를 지정을 하는 경우에는 그 대상을 참조하게 됩니다.

const 콜백함수 = function(e){
    console.log(this, e);
}

document.body.innerHTML += '<h1 id="one">this가 될래요</h1>';
document.getElementById('one')
    .addEventListener('click', 콜백함수); // (1)

(1) 여기서 addEventListener는 내부에서 콜백 함수를 호출할 때 call 메서드의 첫 번째 인자로 addEventListener의 this를 그대로 넘기도록 정의 되어있기 때문에 콜백함수 내부에서 this도 addEventListener의 호출 주체인 HTML 엘리먼트를 참조하게 됩니다.

😎 이렇게 제어권을 넘겨받은 코드가 this를 지정하는 경우입니다.

4. 콜백함수는 함수이다.

😠 콜백함수는 함수입니다. 콜백 함수로 어떤 객체의 메서드를 전달하더라도 그 메서드는 메서드가 아닌 함수로서 호출됩니다.

const 객체 = {
    메서드 : function(){
        console.log(this);
    }
}

객체.메서드(); // { '메서드': [Function: 메서드] }
[1,2,3].forEach(객체.메서드); // (1) global

이렇게 알수있다시피 메서드로 콜백함수를 전달하였지만
this는 전역객체가 나온것을 확인할 수 있습니다.
말그대로 함수로서 호출이 된것입니다.

(1) 그 이유는 콜백함수를 전달할때 객체를 this로 하는 메서드를 그대로 전달한 것이 아니라 객체.메서드가 가리키는 함수만 전달 한것입니다. 그래서 이 함수는 메서드로서 호출할 때가 아닌 한 객체와 직접적인 연관은 없어지게 됩니다.

그래서 forEach에서 직접적으로 this를 바인딩 하지않는 이상 콜백함수 내부에서는 전역객체를 바라보게 됩니다.

5. 콜백함수 내부에 this 바인딩

🙄 위에서 객체의 메서드를 콜백 함수를 전달하면 해당 객체를 this를 바라볼 수 없다는 점을 알수있었습니다.

그러나 해당 객체를 this를 바라보고 싶다면 어떻게 해야될까요?

😥 만약 별도의 인자로 this를 지정할 수 있다면 여기에 원하는 값을 넘겨주면 됩니다. 하지만 별도로 명시할 수 없다면 this의 제어권도 넘겨주게 되는 것이니 사용자가 임의로 변경할 수 없습니다.

😁 방법은 간단합니다. bind 메서드를 사용하면 됩니다.

const 객체 = {
    이름 : '객체1',
    메서드 : function(){
        console.log(this.이름);
    }
};

const 객체2 = {이름:'객체2'};
setTimeout(객체.메서드.bind(객체2),1000); // '객체2' 출력
  • 이렇게 bind메서드를 이용하여 새로운 함수를 반환합니다. 그러면 그 콜백함수의 this는 bind메서드에 지정한 인자값을 참조하게 되고 '객체2'라는 출력값을 얻을 수 있습니다.

🙉 정리

  • 콜백 함수는 다른 코드에 인자로 넘겨줌으로써 그 제어권도 위임
  • 제어권을 넘겨받은 코드는 다음과 같은 제어권을 가짐
    • 실행시점
    • 매개변수
    • this
  • 어떤 함수에 인자로 메서드를 전달하더라도 이는 결국 함수로서 호출
  • 비동기 제어를 위해 콜백 함수를 사용하다 보면 콜백 지옥에 빠지기 쉽다. -> Promise, Generator, async/await등 휼륭한 방법들이 있다. (이 부분에 대해서는 나중에 자세히 다뤄보도록 하겠습니다.)

참고 :
1. 코어자바스크립트
2. 인프런 - 코어자바스크립트

profile
기록 저장소

0개의 댓글