코어 자바스크립트 (콜백함수)

소재현·2022년 11월 9일
0

콜백함수란?

다른 코드의 인자로 넘겨주는 함수
콜백함수를 넘겨받은 코드는 콜백 함수를 필요에 따라 적절한 시점에 시행한다.

콜백함수는 제어권과 관련이 깊다.
callback => 되돌아 호출해달라는 명령
어떤 함수 x를 호출하면서 '특정 조건일 때 함수 y를 실행해서 나에게 알려달라'는 요청을 함께 보낸다.
이 요청을 받은 함수 x의 입장에서는 해당 조건이 갖춰졌는지 여부를 스스로 판단하고 y를 직접 호출한다.

이처럼 콜백 함수는 다른 코드에게 인자로 넘겨줌으로써 그 제어권도 함께 위임한 함수이다.

콜백 함수를 위임받은 코드는 자체적인 내부 로직에 의해 이 콜백함수를 적절한 시점에 실행할 것이다.

제어권

콜백 함수는 다른 코드(함수 또는 메서드)에게 인자로 넘겨줌으로써 그 제어권도 함께 위임

호출 시점

예제 - setInterval

let count = 0;
const timer = setInterval(function () {
  console.log(count);
  if (++count > 4) clearInterval(timer);
}, 300);

// 실행 결과
// 0
// 1
// 2
// 3
// 4
  • 300ms 마다 카운팅 된 숫자를 출력하고 카운트가 4를 넘으면 타이머를 초기화 시켜 종료
  • 300ms 마다 주기적으로 callback 함수가 호출

예제 - setInterval cbFunc 명시적 표현

let count = 0;
const cbFunc = function () {
  console.log(count);
  if (++count > 4) clearInterval(timer);
}
let timer = setInterval(cbFunc, 300);

// 실행 결과
// 0
// 1
// 2
// 3
// 4
  • 콜백 함수를 보다 명시적으로 표현 (cbFunc)
  • cbFunc, setInterval의 호출 주체와 제어권 비교

인자

예제 - Array.prototype.map

const newArr = [10, 20, 30].map(function (currentValue, index) {
  console.log(currentValue, index);
  return currentValue + 5;
});

console.log(newArr);

// 실행 결과
// 10 0
// 20 1
// 30 2
// [15, 25, 35]

예제 - Array.prototype.map 인자 순서 변경

const newArr = [10, 20, 30].map(function (index, currentValue) {
  console.log(index, currentValue);
  return currentValue + 5;
});

console.log(newArr);

// 실행 결과
// 10 0
// 20 1
// 30 2
// [5, 6, 7]
  • 콜백 함수를 호출 할 때 넘기는 인자 값은 이름에 관계 없이 순서대로 값이 전달
  • 전달되는 인자의 순서는 콜백 함수를 호출 주체가 되는 함수(또는 메서드)가 결정

this

  • 콜백 함수도 함수이기 때문에 기본적으로 this가 전역객체를 참조
  • 하지만 제어권을 넘겨 받을 코드에서 콜백 함수에 별도로 this가 될 대상을 지정한 경우에는 그 대상을 참조

예제 - Array.prototype.map 구현

Array.prototype.map = function (callback, thisArg) {
  let mappedArr = [];
  for (let i = 0; i < this.length; i++) {
    const mappedValue = callback.call(thisArg || window, this[i], i, this);
    mappedArr[i] = mappedValue;
  }
  return mappedArr;
}

const result = [10, 20, 30].map(function (value, index) {
  console.log(this, value, index);
  return value + 100;
});

console.log(result);

// 실행 결과
// Window 10 0
// Window 20 1
// Window 30 2
// [110, 120, 130]

const anotherResult = [10, 20, 30].map(function (value, index) {
  console.log(this, value, index);
  return value + 100;
}, [1, 2, 3]);

console.log(anotherResult);

// 실행 결과
// [1, 2, 3] 10 0
// [1, 2, 3] 20 1
// [1, 2, 3] 30 2
// [110, 120, 130]
  • thisArg가 있는 경우에는 해당 값을 콜백 함수의 this로 지정 없는 경우, 전역 객체(window)를 this로 지정

예제 - addEventListener

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

setTimeout(cbFunc, 300);
// 실행 결과
// Window

const arr = [1, 2, 3, 4, 5];
arr.forEach(cbFunc);
// 실행 결과
// Window
// Window
// Window
// Window
// Window

arr.forEach(cbFunc, arr);
// 실행 결과
// [1, 2, 3, 4, 5]
// [1, 2, 3, 4, 5]
// [1, 2, 3, 4, 5]
// [1, 2, 3, 4, 5]
// [1, 2, 3, 4, 5]

document.body.innerHTML += '<button id="a">클릭</button>';
document.body.querySelector('#a')
  .addEventListener('click', cbFunc);
// 실행 결과
// <button id="a">클릭</button>
  • setTimeout
    내부에서 콜백 함수를 호출할 때 call 메서드의 첫번째 인자에 전연 객체를 넘기기 때문에 콜백 함수 내부에서의 this는 전역 객체를 가리킴

  • forEach
    별도의 인자로 this를 받는 경우. 콜백 함수 다음 인자로 this로 지정할 객체를 넘기지 않은 경우에는 this가 전역 객체를 가리키고, this로 지정할 객체를 넘긴 경우에는 this가 해당 객체를 가리킴

  • addEventListener
    내부에서 콜백 함수를 호출 할 때 call 메서드의 첫번째 인자에 addEventListener 메서드의 this를 그대로 넘기도록 정의돼 있기 때문에 콜백 함수 내부에서 this가 addEventListener를 호출 한 주체 HTML 엘리먼트를 가리킴

정리

  • 콜백 함수는 다른 코드에 인자로 넘겨줌으로써 제어권까지 함께 위임한 함수
  • 제어권을 넘겨받은 코드가 다음과 같은 제어권을 가짐
    • 콜백 함수를 호출하는 시점을 스스로 판단해서 실행
    • 콜백 함수를 호출할 때 인자로 넘겨줄 값들 및 그 순서가 정해져 있음
    • 콜백 함수의 this가 무엇을 바라보도록 할지가 정해져 있는 경우도 있음. 정하지 않은 경우에는 전역 객체를 바라봄. 사용자가 임의로 this를 바꾸고 싶을 경우 bind 메서드를 활용하면 됨
  • 어떤 함수에 인자로 메서드를 전달하더라도 이는 결국 함수로서 실행됨
  • 최근의 ECMAScript에는 Promise, Generator, async/await 등 콜백 지옥에서 벗어날 수 있는 방법들이 등장하였음

0개의 댓글