icon안동민 개발노트

고차 함수와 콜백


 고차 함수와 콜백은 자바스크립트의 강력한 기능으로, 함수형 프로그래밍의 핵심 개념입니다.

 이 절에서는 이들의 개념, 사용법, 그리고 실제 응용에 대해 자세히 알아보겠습니다.

고차 함수 (Higher-Order Functions)

 고차 함수는 다음 중 하나 이상을 만족하는 함수입니다.

  1. 함수를 인자로 받는 함수
  2. 함수를 반환하는 함수

 자바스크립트에서 함수는 일급 객체(First-Class Objects)로 취급됩니다.

 이는 함수를 변수에 할당하거나, 다른 함수의 인자로 전달하거나, 함수에서 반환할 수 있음을 의미합니다.

 예시

// 함수를 인자로 받는 고차 함수
function applyOperation(x, y, operation) {
    return operation(x, y);
}
 
// 함수를 반환하는 고차 함수
function multiplyBy(factor) {
    return function(number) {
        return number * factor;
    }
}
 
let double = multiplyBy(2);
console.log(double(5)); // 출력: 10

콜백 함수 (Callback Functions)

 콜백 함수는 다른 함수에 인자로 전달되어, 그 함수의 내부에서 호출되는 함수입니다.

 동기 콜백은 즉시 실행되는 반면, 비동기 콜백은 특정 작업이 완료된 후 실행됩니다.

 예시

// 동기 콜백
[1, 2, 3].forEach(function(item) {
    console.log(item);
});
 
// 비동기 콜백
setTimeout(function() {
    console.log("This is delayed");
}, 1000);

대표적인 고차 함수들

  1. map : 배열의 모든 요소에 함수를 적용하고 새 배열을 반환
let numbers = [1, 2, 3, 4];
let squared = numbers.map(x => x * x);
console.log(squared); // [1, 4, 9, 16]
  1. filter : 조건을 만족하는 요소만 선택하여 새 배열을 반환
let numbers = [1, 2, 3, 4, 5, 6];
let evens = numbers.filter(x => x % 2 === 0);
console.log(evens); // [2, 4, 6]
  1. reduce : 배열의 요소들을 단일 값으로 줄임
let numbers = [1, 2, 3, 4];
let sum = numbers.reduce((acc, cur) => acc + cur, 0);
console.log(sum); // 10

함수 합성과 커링

 함수 합성은 두 개 이상의 함수를 조합하여 새로운 함수를 만드는 기법입니다.

const compose = (f, g) => x => f(g(x));
const addOne = x => x + 1;
const double = x => x * 2;
const addOneThenDouble = compose(double, addOne);
console.log(addOneThenDouble(3)); // 8

 커링은 여러 개의 인자를 받는 함수를 하나의 인자만 받는 함수들의 체인으로 변환하는 기법입니다.

const multiply = (a, b) => a * b;
const curriedMultiply = a => b => a * b;
console.log(curriedMultiply(2)(3)); // 6

콜백 지옥과 해결책

 콜백 지옥은 비동기 작업을 처리할 때 콜백이 중첩되어 코드의 가독성과 유지보수성이 떨어지는 현상입니다.

 콜백 지옥 예시

asyncOperation1(function(result1) {
    asyncOperation2(result1, function(result2) {
        asyncOperation3(result2, function(result3) {
            // 더 많은 중첩된 콜백...
        });
    });
});

 해결책

  1. Promise : 비동기 작업의 최종 완료 또는 실패를 나타내는 객체
asyncOperation1()
.then(result1 => asyncOperation2(result1))
.then(result2 => asyncOperation3(result2))
.then(result3 => {
    // 결과 처리
})
.catch(error => {
    // 오류 처리
});
  1. async/await : Promise를 더 동기적으로 보이게 만드는 문법적 설탕
async function performOperations() {
try {
    let result1 = await asyncOperation1();
    let result2 = await asyncOperation2(result1);
    let result3 = await asyncOperation3(result2);
    // 결과 처리
} catch (error) {
    // 오류 처리
}
}

실제 프로그래밍 예제

 이벤트 처리

function debounce(func, delay) {
    let timeoutId;
    return function(...args) {
        clearTimeout(timeoutId);
        timeoutId = setTimeout(() => func.apply(this, args), delay);
    };
}
 
const efficientResize = debounce(() => {
    console.log('Resized');
}, 250);
 
window.addEventListener('resize', efficientResize);

 비동기 데이터 처리

function fetchData(url) {
    return fetch(url)
        .then(response => response.json())
        .then(data => data.map(item => item.name))
        .catch(error => console.error('Fetching error:', error));
}
 
fetchData('https://api.example.com/users')
    .then(names => console.log(names));

 이러한 예제들은 고차 함수와 콜백을 사용하여 코드의 재사용성과 모듈화를 향상시킵니다. debounce 함수는 다양한 이벤트 핸들러에 재사용될 수 있으며, fetchData 함수는 다양한 API 엔드포인트에 대해 재사용될 수 있습니다.

함수형 프로그래밍에서의 중요성

 고차 함수와 콜백은 함수형 프로그래밍의 핵심 개념입니다.

  1. 추상화 : 복잡한 로직을 간단한 함수로 추상화할 수 있습니다.
  2. 합성 : 작은 함수들을 조합하여 복잡한 동작을 만들 수 있습니다.
  3. 불변성 : 데이터를 변경하는 대신 새로운 데이터를 생성하는 패턴을 촉진합니다.
  4. 순수 함수 : 부작용 없는 함수를 만들어 예측 가능성을 높입니다.

 활용 방안

  • 데이터 변환 및 필터링 파이프라인 구축
  • 비동기 작업의 효율적 관리
  • 이벤트 처리 및 UI 상호작용 구현
  • 재사용 가능한 유틸리티 함수 생성

 고차 함수와 콜백은 자바스크립트 프로그래밍, 특히 함수형 프로그래밍에서 핵심적인 역할을 합니다.

 이들은 코드의 추상화 수준을 높이고, 재사용성과 모듈성을 증가시키며, 복잡한 비동기 작업을 효과적으로 처리할 수 있게 해줍니다.

 고차 함수의 능력을 통해 개발자는 더 선언적이고 표현력 있는 코드를 작성할 수 있습니다.

 예를 들어, map, filter, reduce와 같은 배열 메서드들은 복잡한 데이터 처리 로직을 간결하고 읽기 쉬운 코드로 표현할 수 있게 해줍니다.

 콜백 함수는 비동기 프로그래밍의 기초가 되며, 이벤트 기반 프로그래밍에서 필수적입니다. 그러나 콜백의 과도한 중첩은 콜백 지옥이라는 문제를 야기할 수 있습니다. 콜백 지옥에 대해서는 바로 다음 절에서 다루고 있습니다.

 먼저 이야기하자면 이러한 문제들을 해결하기 위해 Promise와 async/await 같은 현대적인 비동기 패턴이 도입되었습니다. 이들은 비동기 코드를 더 동기적으로 보이게 만들어 가독성과 유지보수성을 크게 향상시킵니다.

 함수 합성과 커링은 함수형 프로그래밍의 고급 기법으로, 더 모듈화되고 재사용 가능한 코드를 작성할 수 있게 해줍니다.

 이러한 기법들은 복잡한 연산을 작은 단위의 함수들로 분해하고, 이들을 조합하여 새로운 함수를 만들 수 있게 합니다.

 실제 애플리케이션에서 고차 함수와 콜백은 다양한 방식으로 활용됩니다. 예를 들어, 이벤트 핸들링, API 호출, 데이터 처리 파이프라인 구축 등에서 중요한 역할을 합니다. 이들을 효과적으로 사용하면 코드의 구조를 개선하고, 재사용성을 높이며, 테스트와 디버깅을 용이하게 만들 수 있습니다.

 결론적으로, 고차 함수와 콜백은 단순히 자바스크립트의 기능이 아니라, 더 나은 코드를 작성하기 위한 강력한 도구입니다. 함수형 프로그래밍의 원칙과 결합하여 사용할 때 복잡한 문제를 해결하는 솔루션으로 활용활 수 있는 현대 웹 개발의 핵심 기술로 자리잡고 있습니다.