Frontend/JavaScript

[JavaScript] 호이스팅과 콜백함수

ayeongjin 2025. 1. 25. 23:54

호이스팅(hoisting)

프로그램에서 변수나 함수를 호출하거나 접근하는 코드가 함수 선언 코드보다 위에 있음에도 불구하고, 마치 선언 코드가 위에 있는 것처럼 동작하는 자바스크립트만의 기능

 

  • 이 코드에서 함수 선언문이 함수 호출보다 아래에 있지만 오류가 발생하지 않는다.
func();

function func() {
  console.log("hello");  // hello
}

 

호이스팅이 발생하는 이유

  • 자바스크립트는 코드를 실행하기 전에 준비 단계를 거치는데 준비 단계에서 중첩 함수가 아닌 함수들은 모두 찾아 미리 생성해 둔다.
  • 자바스크립트 코드는 이런 준비 단계를 거친 다음에 실행되므로 함수 선언 코드를 호출보다 늦게 작성해도 자연스럽게 호출할 수 있다.
  • 자바스크립트의 독특한 특징의 하나인 호이스팅은 코드 내에서 함수 선언의 위치를 강제하지 않기 때문에 더 유연한 프로그래밍을 작성하는 데 도움을 주기도 한다.

 

💡 함수 표현식으로 만든 함수는 함수 선언으로 만든 함수와는 달리 호이스팅되지 않는다.
funcA(); // 출력 : "hello"
funcB(); // 오류 : funcB는 정의되지 않았으며 함수가 아닙니다

// 함수 선언식
function funcA() {
  console.log("func A");
}

// 함수 표현식
let funcB = function () {
  console.log("func B");
};
  • funcA는 함수 선언으로 만들었기 때문에 호이스팅의 대상입니다 → 따라서 함수 선언 전에도 호출 가능
  • funcB에 저장한 함수는 함수 표현식으로 만들었으므로 선언이 아닌 ‘값’으로 취급 → 함수 호이스팅 불가능

 


 

콜백 함수 (Callback Function)

함수는 다른 함수의 인수(인수=값)로도 전달할 수 있는데, 이를 ‘콜백 함수(Callback Function)’라고 한다.

function parentFunc(callBack) { // 매개변수 callBack에는 함수 childFunc이 저장됩니다
  console.log("parent");
  callBack();
}

function childFunc() {
  console.log("child");
}

parentFunc(childFunc); // ①

// 출력
// parent
// child
  1. 함수 선언으로 2개의 함수 parentFunc와 childFunc을 만들고 에서 함수 parentFunc을 호출 → 인수로 함수 childFunc을 전달한다.
  2. 따라서 함수 parentFunc의 매개변수 callback에는 함수childFunc이 저장된다
  3. 함수 parentFunc을 호출하면 먼저 parentFunc은 parent를 콘솔에 출력한다.
  4. 그런 다음 매개변수 callback에 저장된 함수를 호출한다.
  5. 매개변수 callback에는 에서 인수로 전달된 함수 childFunc이 저장되어 있다.
  6. 따라서 함수 callback 을 호출하면 함수 childFunc이 실행되어 ‘child’를 콘솔에 출력한다.
  • 콜백 함수를 인수로 받는 함수를 고차 함수(Higher-Order Function, HOF)라고 한다.

 

1. 콜백 함수가 필요한 이유

function repeat(count) { // ①
  for (let idx = 0; idx < count; idx++) {
    console.log(idx + 1);
  }
}
repeat(5); // 1 2 3 4 5

① 함수 repeat는 매개변수 count만큼 반복하면서 현재의 반복이 몇 번째인지 콘솔에 출력한다.

  • 만약 함수 repeat와 동일한 구조로 반복하는 반복문이지만 다른 기능이 추가적으로 필요하다면 일반적으로 다음과 같이 새 함수를 만든다.
    (함수 repeatDouble은 repeat처럼 전달된 숫자만큼 반복하는 작업은 동일하지만, 반복문에서 수행하는 명령이 조금 다름)
function repeat(count) {
  for (let idx = 0; idx < count; idx++) {
    console.log(idx + 1);
  }
}

function repeatDouble(count) { // ①
  for (let idx = 0; idx < count; idx++) {
    console.log((idx + 1) * 2);
  }
}

repeatDouble(5); // 2 4 6 8 10

💡 함수가 동일한 기능을 갖더라도 특정 부분이 달라 새 함수를 만들게 되면 중복코드가 발생 → 콜백 함수를 사용하여 해결 가능

 

function repeat(count, callBack) { // ③
  for (let idx = 0; idx < count; idx++) { // ④
    callBack(idx + 1);
  }
}

function origin(count) { // ①
  console.log(count);
}

repeat(5, origin); // ②

// 출력 : 1 2 3 4 5

① 매개변수를 콘솔에 출력하는 함수 origin을 만든다.
② 함수 repeat를 호출하고 인수로 5와 함수 origin을 전달한다.
③ 함수 repeat가 호출되면 매개변수 count에는 숫자 5를 저장하고, callback에는 함수 origin을 저장한다.
④ 0부터 4까지 총 5회 반복할 때마다 매개변수 callback에 저장한 함수 origin을 호출하고 idx + 1을 인수로 전달한다. 따라서 함수 origin은 함수 repeat의 반복문에서 총 5회 호출되면서 숫 자 1부터 5까지 콘솔에 출력

  • 만일 함수 repeat에서 반복문의 동작을 변경하고 싶다면, 새 함수를 만들어 repeat 의 인수로 전달
function repeat(count, callBack) { // ③
  for (let idx = 0; idx < count; idx++) {
    callBack(idx + 1);
  }
}

function origin(count) {
  console.log(count);
}

function double(count) { // ①
  console.log(count * 2);
}

repeat(5, double); 

// 출력 : 2 4 6 8 10

① 매개변수에 2를 곱해 콘솔에 출력하는 함수 double을 만듭니다.
② 함수 repeat의 인수로 함수 double을 전달합니다. 이제 함수 repeat의 매개변수 callback에는 함수 double이 저장됩니다.
③ 함수 repeat의 반복문에서 반복할 때마다 매개변수 callback에 저장된 함수 double을 호출하고 인수로 idx + 1을 전달합니다. 따라서 2 4 6 8 10이 콘솔에 출력됩니다.

  • 만일 함수 repeat 내에서 또 다른 일을 하고 싶다면, 새 함수를 만들고 인수로 전달해 콜백 함수를 교체하면 됩니다. 콜백 함수를 이용하면 상황에 맞게 하나의 함수가 여러 동작을 수행하도록 만들 수 있습니다.

 

2. 함수 표현식을 이용한 콜백 함수

  • 콜백 함수는 함수 표현식으로도 만들 수 있다.
function repeat(count, callBack) {
  for (let idx = 0; idx < count; idx++) {
    callBack(idx + 1);
  }
}

const double = function (count) { // ①
  console.log(count * 2);
};

repeat(5, double); // ② 

// 출력 : 2 4 6 8 10

① 받은 인수에 2를 곱해 콘솔에 출력하는 익명 함수를 만들어 double에 저장
② 변수 double에 저장된 함수를 repeat의 인수로 전달해 콜백 함수로 사용

  • 변수 double에 저장한 익명 함수를 다시 사용할 필요가 없는 상황이라면, 다음과 같이 익명 함수를 직접 인수 형태로 전달 → 코드 단축 가능
function repeat(count, callBack) {
  for (let idx = 0; idx < count; idx++) {
    callBack(idx + 1);
  }
}

repeat(5, function (count) { // ①
  console.log(count * 2);
});

// 출력 : 2 4 6 8 10

① 함수 repeat를 호출하며 첫 번째 인수로는 숫자 5, 두 번째 인수로는 콜백 함수로 활용할 익명 함수를 직접 생성해 전달한다. 그럼 익명 함수는 함수 repeat의 매개변수 callback에 저장되어 repeat 내에서 호출할 수 있게 된다