Computer >> 컴퓨터 >  >> 프로그래밍 >> JavaScript

자바스크립트 고차 함수(HOF) 완벽 가이드: 개념부터 실전 활용까지

개발자라면 일반적인 자바스크립트 함수를 사용해 본 경험이 있을 것입니다. 흔히 1차 함수(first-order function)라고 불리는 이 함수들은 매개변수로 함수를 받거나 함수를 반환하지 않습니다.

function hello(name) {
   return "Hello," + " " + name
}

console.log(hello("Career Karma")); // Hello, Career Karma

이 글에서는 고차 함수(Higher Order Function, HOF)에 대해 다룹니다. 고차 함수는 함수를 인자로 전달하거나 함수를 반환함으로써 코드를 더 간결하고 가독성 있게 만들어 주는 함수입니다. 기본적인 예제를 통해 HOF와 함수형 프로그래밍의 개념을 소개하고, 고차 함수 구조를 기반으로 동작하는 대표적인 고급 배열 메서드 두 가지도 함께 살펴보겠습니다.

고차 함수 기본 예제

자바스크립트에서는 여러 가지 방식으로 고차 함수를 활용할 수 있습니다.

계산기 예제

먼저 콜백 함수를 인자로 받아 해당 콜백에 인수를 전달해 실행하는 기본적인 HOF부터 살펴보겠습니다.

// 고차 함수
function higherOrderFunction(num1, num2, cb) {
   return cb(num1, num2); // cb 함수를 호출하고 인수를 콜백에 전달합니다.
}

// 콜백 함수들
function add(num1, num2) {
   return num1 + num2;
}
function multiply(num1, num2) {
   return num1 * num2;
}
function divide(num1, num2) {
   return num1 / num2;
}
function subtract(num1, num2) {
   return num1 - num2;
}
function modulo(num1, num2) {
   return num1 % num2;
}

console.log(higherOrderFunction(43, 13, add)); // 56

여기에는 두 종류의 함수가 있습니다. 하나는 콜백을 반환하는 고차 함수이고, 다른 하나는 두 숫자에 연산을 수행하는 1차 함수들의 집합입니다. 코드 마지막에서 higherOrderFunction()을 호출하면, 이 함수는 전달된 콜백(cb)을 주어진 매개변수와 함께 호출한 결과를 반환합니다. 모든 산술 연산자에 대한 콜백 함수를 미리 작성해 두었다면, higherOrderFunction을 통해 필요한 어떤 연산이든 손쉽게 호출할 수 있습니다.

이벤트 리스너

고차 함수의 또 다른 대표적인 예는 DOM(문서 객체 모델) 요소에 이벤트 리스너를 추가할 때입니다. 아래 예제를 보겠습니다.

<!DOCTYPE html>
<html>
   <body>
       <button>Click Me!</button>
       <script async defer>
           const button = document.querySelector("button");
           button.addEventListener("click", (e) => {
               alert("The button has been clicked!");
           })
       </script>
   </body>
</html>

이 예제에서는 HTML로 버튼을 만들고 자바스크립트로 해당 버튼을 선택한 뒤 이벤트 리스너를 추가했습니다. 이벤트 리스너의 구조는 간단한 고차 함수와 같습니다. 즉, 두 번째 인자로 익명 함수를 받습니다.

자바스크립트 고차 함수(HOF) 완벽 가이드: 개념부터 실전 활용까지

위 이미지에서 하이라이트된 부분이 바로 고차 함수입니다.

고급 배열 메서드

자바스크립트 내장 배열 메서드는 ES6에서 새롭게 등장한 특별한 고차 함수들로, 배열을 반복하면서 값을 조작하거나 조작된 값으로 이루어진 완전히 새로운 배열을 반환할 때 사용할 수 있습니다.

자바스크립트로 점점 더 복잡한 문제를 해결하게 되면, 배열을 순회할 때 작성하던 로직을 추상화하는 방법을 고민하게 됩니다. 이러한 고차 함수 배열 메서드를 적극적으로 활용하면 더 나은 자바스크립트 개발자로 성장할 수 있습니다.

예를 들어 교수(professor) 이름으로 이루어진 배열이 있다고 가정해 보겠습니다.

자바스크립트 고차 함수(HOF) 완벽 가이드: 개념부터 실전 활용까지

forEach

ES6 이전에는 배열을 순회하며 각 항목을 조작하려면 다음과 같이 작성해야 했습니다.

function forEachES5(arr){
   for(let i = 0; i < arr.length; i++) {
       arr[i] = "Professor " + arr[i];
   }
   return arr;
}

console.log(forEachES5(professors));

ES6 문법에서는 forEach 메서드를 사용해 코드를 훨씬 간결하게 줄일 수 있습니다.

function forEachES6(arr) {
   arr.forEach((professor, index, origArr) => {
       origArr[index] = "Professor " + professor;
   });
   return arr;
}

forEach 메서드는 첫 번째 매개변수로 콜백 함수를 받기 때문에 고차 함수입니다. 이 콜백 함수는 배열의 각 항목에 수행할 "동작(action)"이라고 할 수 있습니다. 또한 forEach는 선택적으로 두 번째 매개변수로 인덱스, 세 번째 매개변수로 배열 자체를 추가로 받을 수 있습니다.

forEach 메서드(그리고 다른 내장 배열 메서드들도 마찬가지)에서는 매개변수의 순서가 중요합니다. 첫 번째는 항상 콜백 함수, 두 번째는 항상 배열에서 해당 항목의 인덱스, 세 번째는 항상 배열 자체의 복사본입니다.

forEach 메서드는 사실상 자바스크립트에서 for 루프를 표현하는 또 다른 방법입니다. 이 메서드는 아무것도 반환하지 않으며, 지정한 동작대로 기존 배열을 직접 조작해 그 결과를 작업 중인 배열에 저장합니다.

map

forEach 메서드와 가장 유사한 메서드는 map입니다. 작동 방식은 거의 같지만, map은 새로운 배열을 반환한다는 점이 다릅니다. 따라서 콜백 함수 안에서 무엇을 조작하더라도 원본 배열에는 영향을 주지 않습니다.

ES6 이전에 map과 같은 기능을 구현하려면 어떻게 했는지 살펴보겠습니다.

function mapES5(arr){
   let newArr = [];
   for(let i = 0; i < arr.length; i++) {
       newArr.push("Professor " + arr[i]);
   }
   return newArr;
}

보시다시피 for 루프 바깥에서 새 배열을 먼저 생성한 뒤 새로운 값을 push해야 했습니다. 게다가 새 배열을 다른 곳에서 사용하려면 반드시 직접 반환해야 했습니다.

ES6의 map 메서드를 사용하면 이런 로직을 추상화해 훨씬 읽기 쉬운 코드를 작성할 수 있습니다.

function mapWithES6(arr) {
   const mapped = arr.map(professor => {
       return "Professor " + professor;
   })
   return mapped;
}

map 메서드, 그리고 reduce나 filter처럼 유사하게 동작하는 배열 메서드의 특별한 점은 결과를 변수에 할당해 반환하거나 함수 전체를 그대로 반환할 수 있다는 것입니다. 새 배열에 일일이 push할 필요가 없습니다. map 메서드가 대신 처리해 주기 때문입니다. 단, map 메서드의 콜백 함수 안 로직에는 반드시 반환값(return)을 포함해야 한다는 점을 잊지 마세요.

마무리

고차 함수는 자바스크립트 개발자로 성장하는 데 반드시 이해해야 할 매우 중요한 개념입니다. 로직을 추상화해 코드 가독성을 높여주고, 경우에 따라서는 성능 개선 효과까지 얻을 수 있습니다.

이 튜토리얼에서는 기본적인 계산기 예제부터 이벤트 리스너, 그리고 forEach와 map 같은 고급 배열 메서드까지 고차 함수를 작성하고 활용하는 다양한 방법을 살펴봤습니다. 이 개념을 확실히 익혔다면 이제 더 복잡한 문제 해결에 도전할 준비가 된 것입니다.