Skip to content

일급 객체와 고차 함수

💡 Key Concepts

  • 일급 (First-class)
    : 어떤 값을 변수에 저장하고, 함수의 인자로 전달하거나 함수의 결과로 반환할 수 있음을 의미한다.
  • 자바스크립트에서 함수가 일급 객체인 이유
    : 함수를 일반 값처럼 변수에 할당하고, 다른 함수의 인자나 반환 값으로 사용할 수 있기 때문이다.
  • 고차 함수
    : 다른 함수를 인자로 받거나, 함수를 결과로 반환하는 함수다.
  • 어플리케이티브(Applicative) 프로그래밍
    : 함수를 값으로 다루고, 필요한 시점에 특정 인자를 적용해 실행하는 프로그래밍 스타일이다.
  • 클로저
    : 함수가 내부 함수를 생성해 반환할 때, 반환된 함수가 자신이 생성될 당시의 외부 환경(변수)을 기억하는 개념이다.

이 개념들은 함수를 일급 값으로 다룰 때, 고차 함수와 클로저를 통해 함수형 프로그래밍의 기반을 이룬다.

평가 (Evaluation)

코드가 실행되어 값을 만들어내는 과정

함수형 프로그래밍에서 함수를 값으로 다룬다는 것은, 단순히 함수를 전달할 수 있다는 의미에 그치지 않는다.

이는 곧, 함수의 평가 시점을 코드로 다룰 수 있다는 뜻이다.
즉, 실행 시점을 로직이 아닌 구조로 표현할 수 있게 된다.

함수형 프로그래밍에서 Evaluation이 중요한 이유

대표적인 평가 전략:

  • 즉시 평가(Eager Evaluation): 값이 필요하지 않아도 즉시 계산
  • 지연 평가(Lazy Evaluation): 값이 실제로 필요한 시점에 계산

이러한 전략들은 평가 시점을 다루며, 함수형 프로그래밍의 동작 방식과 성능에 큰 영향을 준다.

🧩 Evaluation

평가(Evaluation)는 프로그래밍에서 표현식이 실제로 실행되어 값(value)으로 바뀌는 전 과정을 포괄하는 용어이다. 단순히 수를 더하는 ‘계산(calculation)’보다 더 넓은 개념이기 때문에, 개발자들은 ‘평가’라는 표현을 쓴다.

구분계산 (Calculation)평가 (Evaluation)
의미수학적인 연산을 수행해
숫자 결과를 얻는 것
표현식(expression)이 실행되어 값(value)으로 바뀌는 과정 전체
예시2 + 3 = 5x + 3 → x가 2일 때 → 2 + 35
범위숫자 연산 중심변수 참조, 함수 호출, 조건문 분기 등도 포함

즉, 평가는 단순한 수학 연산을 넘어, 코드의 표현식을 실제로 실행해 최종 값을 만들어내는 과정 전체를 의미한다.

js
const x = 10;
const y = x * 2 + 1;
  • x * 2 + 1;이라는 표현식이 평가되어 21이라는 값을 만들어 낸다.
    이 전체 과정을 Evaluation이라고 부른다.

일급 객체 (First-Class Object)

일급 객체란 프로그래밍 언어에서 다른 값들과 동등하게 취급되는 객체를 말한다.

js
const a = 10;

// 함수도 값처럼 변수에 할당할 수 있다.
const add10 = (a) => a + 10;

// 함수는 다른 함수에 인자로 전달할 수 있고
add10(a);

// 함수의 실행 결과도 값이 되어 변수에 담을 수 있다.
const r = add10(a);
console.log(r); // 20

일급 객체의 조건:

  • 값으로 다룰 수 있다.
  • 변수에 담을 수 있다.
  • 함수의 인자로 사용될 수 있다.
  • 함수의 결과로 사용될 수 있다.

자바스크립트에서는 함수가 일급 객체이기 때문에, 고차 함수의 인자나 반환값으로 자유롭게 사용할 수 있다.


일급 함수 (First-Class Function)

자바스크립트에서 함수는 일급 객체다.
즉, 숫자나 문자열처럼 함수를 으로 다룰 수 있으며, 이를 통해 조합성추상화의 도구로 활용할 수 있다.

앞서 일급 객체는 일반적인 개념이었다면, 일급 함수는 자바스크립트에서 함수가 일급 객체로 동작하는 구체적인 예시를 보여준다.

일급 함수의 특징

1. 값으로 다룰 수 있다.

함수 자체를 값처럼 다루어 출력할 수 있다.

js
const add10 = (a) => a + 10;
console.log(add10); // (a) => a + 10

2. 변수에 담을 수 있다.

함수를 변수에 저장해 필요할 때 호출할 수 있다.

js
const add10 = (a) => a + 10;
console.log(add10(10)); // 20

3. 함수의 인자로 사용할 수 있다.

함수를 다른 함수의 인자로 전달할 수 있다.
run은 전달받은 함수 f값 v에 적용하여 실행하는 고차 함수이다.

js
const add10 = (a) => a + 10;
const run = (f, v) => f(v);

console.log(run(add10, 5)); // 15

4. 함수의 결과로 사용할 수 있다

함수를 반환하고, 반환된 함수를 나중에 실행할 수 있다.

js
const makeFunc = () => () => 1;

const f1 = makeFunc();
console.log(f1); // () => 1
console.log(f1()); // 1

요약

  • 함수는 값처럼 변수에 저장, 인자로 전달, 결과로 반환될 수 있다.
  • 이러한 성질 덕분에 조합성과 추상화가 가능해진다.
  • 함수형 프로그래밍은 바로 이 일급 함수 특성을 기반으로 한다.

고차 함수 (Higher-Order Functions)

고차 함수란 함수를 값으로 다루는 함수를 말한다.

  • 함수를 인자로 받거나
  • 함수를 반환하는 함수

이러한 함수들은 반복, 조건, 실행 시점 같은 패턴을 함수로 추상화하여 코드를 더 재사용 가능하고 선언적으로 만든다.

1. 함수를 인자로 받아서 실행하는 고차 함수

아래 예제는 어떤 함수를 실행할지를 외부에서 결정하도록 만든 고차 함수다.

js
const apply1 = (f) => f(1);
const add2 = (a) => a + 2;

console.log(apply1(add2)); // 3
// === add2(1)
// === ((a) => a + 2)(1)

console.log(apply1((a) => a - 1)); // 0
// === ((a) => a - 1)(1)
  • apply1은 함수 f를 받아서, 그 함수에 1을 적용해 실행한다.
  • apply1은 함수의 내부 로직에 관심이 없고, 오직 언제, 어떤 값으로 실행할지만 책임진다.
  • 즉, 실행 로직과 실행 대상(함수)을 분리한 구조다.

실행할 동작을 함수로 외부에서 주입받는 패턴


2. 반복 패턴을 추상화한 고차 함수

다음 예제는 반복이라는 패턴 자체를 함수로 추상화한 고차 함수다.

js
const times = (f, n) => {
  let i = -1;
  while (++i < n) f(i);
};

times(console.log, 3);
// 0
// 1
// 2

times((a) => console.log(a + 10), 3);
// 10
// 11
// 12
  • times는 얼마나 반복할지 n 무엇을 실행할지 f를 분리한다.
  • 반복 제어는 times가 담당하고, 실제 실행할 동작은 함수로 외부에서 전달된다.
js
// 내부에서 실제로 일어나는 일
f(0);
f(1);
f(2);
  • 이 구조 덕분에 반복 방식은 고정하고, 행동만 바꿀 수 있다.

🧩 어플리케이티브(Applicative) 프로그래밍

함수를 값으로 다루고, 필요한 시점에 특정 인자를 적용해 실행하는 방식은 어플리케이티브 스타일의 프로그래밍이라고 부른다.


3. 함수를 만들어 반환하는 함수 (클로저)

아래 예제는 함수를 만들어 반환하는 고차 함수다.

js
// 1. addMaker(10) 실행
const addMaker = (a) => (b) => a + b;
const add10 = addMaker(10);

// 2. 이 시점에 a = 10인 환경이 생성됨
// 3. addMaker의 실행은 끝났지만, 반환된 함수는 a를 여전히 참조할 수 있음

console.log(add10(5)); // 15
// add10 내부: (b) => a + b
// a는 이미 사라진 addMaker의 변수지만 클로저 덕분에 여전히 10을 기억하고 있음

클로저란?

  • 함수가 자신이 생성될 당시의 렉시컬 환경(Lexical Environment)을 기억하는 것
  • 외부 함수의 실행이 끝나도, 내부 함수는 외부 변수에 접근할 수 있다.
  • addMaker는 함수를 반환하는 고차 함수이고, 반환된 함수는 외부 변수 a를 기억하는 클로저다

이렇게 함수 + 함수가 만들어질 당시의 환경을 함께 기억하는 것을 클로저(Closure)라고 부른다.


고차 함수와 클로저의 활용 예시

이 개념들은 이론에 그치지 않고, 실제 개발에서 자주 사용된다.

1. 배열 메서드 (고차 함수)

js
const numbers = [1, 2, 3, 4, 5];

// map: 함수를 인자로 받아 각 요소를 변환
const doubled = numbers.map((n) => n * 2);

// filter: 함수를 인자로 받아 조건에 맞는 요소만 선택
const evens = numbers.filter((n) => n % 2 === 0);

// reduce: 함수를 인자로 받아 누적 연산
const sum = numbers.reduce((acc, n) => acc + n, 0);

2. React Hook과 클로저

jsx
function Counter() {
  const [count, setCount] = useState(0);

  // handleClick은 count를 기억하는 클로저
  const handleClick = () => {
    console.log(count); // 현재 count 값을 기억
    setCount(count + 1);
  };

  return <div>Count: {count}</div>;
}
jsx
// useEffect의 의존성 배열과 클로저
useEffect(() => {
  // 이 함수는 count를 기억하는 클로저
  console.log(count);
}, [count]); // count가 변경될 때마다 새로운 클로저 생성

3. 커스텀 Hook (함수를 반환)

jsx
// 함수를 반환하는 고차 함수 패턴
function useToggle(initialValue = false) {
  const [value, setValue] = useState(initialValue);

  // toggle 함수는 value를 기억하는 클로저
  const toggle = () => setValue(!value);

  return [value, toggle];
}

// 사용
function App() {
  const [isOpen, toggleOpen] = useToggle();

  return <div>{isOpen ? 'Open' : 'Closed'}</div>;
}

4. 이벤트 핸들러 팩토리

jsx
// 함수를 반환하는 고차 함수
function createHandler(id) {
  return () => {
    console.log(`Clicked item ${id}`);
  };
}

function List() {
  const items = [1, 2, 3];

  return (
    <ul>
      {items.map((id) => (
        <li key={id} onClick={createHandler(id)}>
          Item {id}
        </li>
      ))}
    </ul>
  );
}

이처럼 고차 함수와 클로저는 React 개발에서 핵심적인 개념으로, 상태 관리, 이벤트 처리, Hook 구현 등 다양한 곳에서 활용된다.