고차 함수

언어로서의 자바스크르빝는 함수를 데이터로 다룬다. 데이터 영역에서 함수를 전달할 수 있는 강력한 개념도 있다.
인자로 다른 함수를 전달받는 함수를 고차 함수라고 한다.

데이터의 이해

프로그래머로서 데이터로 동작되는 프로그램을 알아야한다. 데이터는 실행할 프로그램을 작성하는 과정에 있어 중요하다.
따라서 모든 프로그래밍 언어는 프로그래머가 작업할 데이터를 제공한다.

자바스크립트 데이터형 이해

자바스크립트는 다음과 같은 데이터형을 지원한다.

  • 숫자 number
  • 문자열 string
  • 불리언 boolean
  • 객체 object
  • 널 null
  • 정의되지 않은 undefined

자바스크립트에서는 함수군의 데이터형도 있다. function 데이터형의 경우 string 과 유사하므로, 변수를 전달하고
저장 등을 할 수 있다. 함수는 프로그래밍 언어가 다른 데이터형으로 사용하게 허용하게 하는 경우 중요하므로, 변수로 지정되고,
인자를 전달하고, 문자열 및 숫자 데이터와 유사하게 다른 함수에서 반환될 수 있다.

함수 저장

함수는 데이터다. 즉 변수로 저장할 수 있다.

1
let fn = () => {};

fn 은 함수 데이터형을 가리키는 변수다. 다음 코드를 실행해서 fn 이 function 형인 것을 확인할 수 있다.

1
2
typeof fn
=> "function"

함수 전달

인자의 데이터형을 콘솔에 출력하는 함수를 만들어 본다.

1
let tellType = arg => console.log(typeof arg);

tellType 함수에 인자를 하나 전달해본다.

1
2
3
let data = 1;
tellType(data);
=> number

이번에는 함수에 대한 참조를 변수로 전달해본다.

1
2
3
let dataFn = () => console.log('function');
tellType(dataFn);
=> function

마지막으로 tellType 이 전달된 인자를 실행하게 변경해본다.

1
2
3
4
5
6
7
let tellType = arg => {
if(typeof arg === 'function') {
arg();
} else {
console.log('data: ', arg);
}
}

전달된 arg 변수가 function 형인지 확인해서 function 형이라면 호출한다.

함수 반환

자바스크립트에서 함수는 간단한 데이터이므로, 다른 함수로도 반환이 가능하다.

문자열을 반환하는 crazy 함수
1
let crazy = () => { return String; }

crazy 함수는 String 함수를 가리키는 함수 참조를 반환한다.

1
2
crazy();
=> String() { [native code] }

crazy 함수 호출은 String 함수를 반환한다. 단순히 함수 참조를 반환하며, 함수를 실행하지는 않는다.
반환된 함수 참조로 다음과 같이 호출할 수 있다.

1
2
3
4
5
6
7
8
// 1.
let fn = crazy();
fn("HOC");
=> "HOC"

// 2.
crazy()("HOC");
=> "HOC"

추상화와 고차 함수

일반적으로, 고차 함수는 일반적인 문제를 추출하고자 작성된다. 다시 말해 고차 함수는 추상화를 정의하는 것이다.

고차 함수를 통한 추상화

forEach 를 고차 함수를 사용하여 만든 예제 코드를 살펴본다.

1
2
3
4
5
const forEach = (array, fn) => {
for(let i=0; i < array.length; i++) {
fn(array[i]);
}
}

위의 forEach 함수는 배열을 순회하는 문제를 추상화했다. forEach API 사용자는 forEach 함수에서 순회 부분이
어떻게 구현됐는지 이해할 필요가 없으므로, 이 문제를 추상화했다.

forEach 는 기본적으로 배열을 순회한다.
배열 말고 객체를 순회하는 단계는 다음과 같다.

  1. 주어진 객체의 모든 키를 반복
  2. 키에 해당하는 각 객체를 확인
  3. 2단계가 확인되면 키의 값을 얻음.
forEachObject 추상화
1
2
3
4
5
6
7
const forEachObject = (obj, fn) => {
for (var property in obj) {
if (obj.hasOwnProperty(property)) {
fn(property, obj[property]);
}
}
}
forEachObject 실행
1
2
3
4
let object = {a:1, b:2};
forEachObject(object, (k,v) => console.log(k + ":" + v));
=> a:1
=> b:2

forEach 와 forEachObject 함수 모두 고차 함수이므로, 개발자가 순회 부분을 추상화해 함수를 전달받아 작업할 수 있다.
이러한 순회 함수를 추상화했으므로, 간결한 코드로 철저히 테스트할 수 있다.
이번에는 제어 흐름을 다루는 추상화 방법을 구현해본다.

unless 함수는 참이나 거짓인 논리형을 취하는 간단한 함수다.

unless
1
2
3
const unless = (predicate, fn) => {
if (!predicate) fn();
}

unless 함수를 활용하여 배열에서 짝수를 찾고자 간단한 코드를 작성할 수 있다.

1
2
3
4
5
6
const array = [1,2,3,4,5,6,7];
forEach(array, number => {
unless((number % 2), () => {
console.log(number, ' is even');
});
});

데이터를 저장하는 모든 곳에서 함수를 이용할 수 있다. 다시 말해 함수는 저장할 수도, 전달될 수도, 다른 데이터형처럼 재할당될 수도 있다.
자바스크립트의 이 강력한 특징은 함수가 다른 함수에 전달되는 고차 함수를 가능케한다. 고차 함수란 다른 함수를 인자로 취하고
함수를 반환하는 함수라는 것을 기억해야 한다.

참조: 함수형 자바스크립트 입문 2/e

댓글

You need to set client_id and slot_id to show this AD unit. Please set it in _config.yml.