시스템아 미안해
Chapter 5. 고차 함수(Higher-Order Functions) 본문
큰 프로그램과 추상화의 필요성
프로그램이 커질수록 버그가 숨어들 자리가 많아진다. 같은 기능이라도, 코드를 짧고 추상화된 방식으로 표현하면 오류 가능성이 줄어든다.
예를 들어 1부터 10까지 더하는 프로그램을 보자.
// 첫 번째 버전: while 루프
let total = 0, count = 1;
while (count <= 10) {
total += count;
count++;
}
console.log(total);
// 두 번째 버전: 추상화된 버전
console.log(sum(range(1, 10)));
두 번째 버전은 sum과 range라는 함수를 사용했다. 내부적으로는 여전히 루프를 돌지만, **“범위(range)와 합(sum)”**이라는 문제 본질에 맞는 단어를 썼기 때문에 더 읽기 쉽고 정확하다.
추상화(Abstraction)
추상화는 세부 구현을 감추고, 더 높은 수준에서 문제를 표현하는 방법이다.
예를 들어 레시피를 생각해보자.
- 저수준 레시피:
“양파를 반으로 자른 뒤 칼로 잘게 잘라서 냄비에 넣어라. 셀러리를 칼로 잘라 넣어라. 당근을 칼로 잘라 넣어라…” - 고수준 레시피:
“양파 반 개, 셀러리 줄기 하나, 당근 하나를 잘라서 냄비에 넣어라.”
둘 다 같은 동작을 하지만, 후자가 더 명확하다.
프로그래밍도 마찬가지다. 너무 낮은 수준에서만 작업하면 의도를 파악하기 어렵다. 추상화를 통해 **“내가 무엇을 하고 싶은가”**를 표현해야 한다.
반복 추상화
자바스크립트는 반복을 루프로 표현한다.
for (let i = 0; i < 10; i++) {
console.log(i);
}
하지만 “어떤 일을 N번 한다”라는 개념을 함수로 추상화할 수도 있다.
function repeat(n, action) {
for (let i = 0; i < n; i++) {
action(i);
}
}
repeat(3, console.log);
// → 0, 1, 2
여기서 action은 함수 값으로 전달된다.
즉, 단순히 숫자를 출력하는 것뿐만 아니라, 원하는 동작을 자유롭게 넣을 수 있다.
let labels = [];
repeat(5, i => labels.push(`Unit ${i + 1}`));
console.log(labels);
// → ["Unit 1", "Unit 2", "Unit 3", "Unit 4", "Unit 5"]
이렇게 하면 반복 자체는 repeat 함수로 추상화하고, 반복할 동작만 전달하면 된다.
고차 함수란?
다른 함수를 인자로 받거나 새로운 함수를 반환하는 함수를 고차 함수(Higher-Order Function)라고 한다.
자바스크립트에서는 함수가 값이므로, 함수를 다루는 함수가 자연스럽게 가능하다.
새로운 함수를 만들어내는 함수
function greaterThan(n) {
return m => m > n;
}
let greaterThan10 = greaterThan(10);
console.log(greaterThan10(11)); // true
함수를 감싸는 함수
function noisy(f) {
return (...args) => {
console.log("calling with", args);
let result = f(...args);
console.log("returned", result);
return result;
};
}
noisy(Math.min)(3, 2, 1);
// → calling with [3, 2, 1]
// → returned 1
새로운 제어 흐름을 만드는 함수
function unless(test, then) {
if (!test) then();
}
repeat(3, n => {
unless(n % 2 == 1, () => console.log(n, "is even"));
});
// → 0 is even
// → 2 is even
배열 메서드 forEach도 대표적인 고차 함수다.
["A", "B"].forEach(l => console.log(l));
// → A
// → B
배열 메서드: filter, map, reduce
자바스크립트 배열은 고차 함수를 적극 활용한다.
filter: 조건에 맞는 값만 추출
let living = SCRIPTS.filter(s => s.living);
map: 새 배열로 변환
let names = living.map(s => s.name);
reduce: 배열을 하나의 값으로 요약
let total = [1, 2, 3, 4].reduce((a, b) => a + b, 0);
// → 10
예를 들어 가장 많은 문자를 가진 스크립트를 찾으려면:
function characterCount(script) {
return script.ranges.reduce((count, [from, to]) =>
count + (to - from), 0);
}
console.log(SCRIPTS.reduce((a, b) =>
characterCount(a) < characterCount(b) ? b : a));
// → {name: "Han", …}
텍스트 분석 예제
문자열 속 문자가 어떤 문자 체계(script)에 속하는지 분석해보자.
function textScripts(text) {
let scripts = countBy(text, char => {
let script = characterScript(char.codePointAt(0));
return script ? script.name : "none";
}).filter(({name}) => name != "none");
let total = scripts.reduce((n, {count}) => n + count, 0);
return scripts.map(({name, count}) =>
`${Math.round(count * 100 / total)}% ${name}`
).join(", ");
}
console.log(textScripts('英国的狗说"woof", 俄罗斯的狗说"тяв"'));
// → 61% Han, 22% Latin, 17% Cyrillic
Strings and Character Codes
문자열을 다룰 때 주의할 점은, 자바스크립트가 UTF-16을 사용한다는 것이다.
대부분의 문자는 하나의 16비트 단위로 표현되지만, 이모지나 일부 문자는 두 개의 단위를 사용한다.
let horseShoe = "🐴👟";
console.log(horseShoe.length); // 4 (코드 단위 개수)
console.log(horseShoe.codePointAt(0)); // 128052 (말 이모지의 실제 코드)
따라서 문자열을 문자 단위로 순회할 때는 for/of와 codePointAt을 사용해야 한다.
let roseDragon = "🌹🐉";
for (let char of roseDragon) console.log(char);
// → 🌹
// → 🐉
Exercises
책에서 제시하는 연습 문제는 다음과 같다.
- Flattening: 배열의 배열을 하나의 배열로 평탄화하기 (reduce + concat)
- Your own loop: 테스트 함수, 업데이트 함수, 본문 함수를 받아 루프처럼 동작하는 함수 만들기
- Everything: every 메서드를 루프 버전과 some을 활용한 버전으로 구현하기
- Dominant writing direction: 문자열의 지배적인 쓰기 방향(ltr/rtl/ttb) 판별하기
정리
- 고차 함수는 함수를 값으로 다루며, 추상화를 가능하게 한다.
- 배열의 고차 메서드(forEach, filter, map, reduce, some, every)는 실무에서 매우 자주 쓰인다.
- 문자열 처리에서는 UTF-16 때문에 코드 단위와 실제 문자가 다를 수 있다는 점을 주의해야 한다.
- 고차 함수는 코드를 짧게 만들 뿐 아니라, 문제의 본질에 맞는 언어로 표현하게 해준다.
'책 > Eloquent Javascript' 카테고리의 다른 글
| Chapter 8. Bugs and Errors (0) | 2025.10.20 |
|---|---|
| Chapter 6. The secret life of objects (0) | 2025.10.01 |
| Chapter 4. Data Structure: Objects And Arrays (0) | 2025.09.29 |
| Chapter 3. Functions (0) | 2025.09.25 |
| Chapter2. Program Structure (0) | 2025.09.24 |