고차함수 21.03.16
in Dev on Java Script
일급 객체(first-class citizen) 특징
- 변수에 할당(assignment) 가능 (ex: function expression)
- 다른 함수의 인자(argument)로 전달 가능
- 다른 함수의 결과로서 리턴
위 특징들은 함수를 데이터(string, number, boolean, array, object)를 다루듯이 함수를 다룰 수 있다는 걸 의미. 변수에 저장할 수 있기 때문에 함수를 배열의 요소나 객체의 속성값으로 저장하는 것도 가능.
함수 표현식(function expression) : 함수 선언식(function declaration)과 다르게 호이스팅(hoisting)이 적용 안됨.
함수 선언식의 호이스팅에 지나치게 의존하는 것은 코드의 유지 보수 측면에서 좋지 않습니다. 코드 리뷰나 디버깅을 할 때 코드를 위 아래로 왔다 갔다하게 될 수 있다. 함수 선언식의 경우, 어느 위치에나 함수를 선언할 수 있고 함수의 실행 위치도 중요하지 않기 때문이다. 반면, 함수 표현식은 함수의 할당과 실행의 위치가 중요하기 때문에 코드의 위치가 어느 정도 예측 가능하다. 호이스팅을 제외하면 함수 선언식과 함수 표현식의 차이는 크게 없어 보이고, 실제로도 그렇다. 다만 함수 표현식의 경우, 함수가 변수에 저장될 수 있다는 사실을 좀 더 분명하게 드러낼 수 있다.
함수 표현식을 사용하자!
고차 함수(higher-order function) : 함수를 인자(argument)로 받거나 함수를 리턴하는 함수.
콜백 함수(callback function): 다른 함수(caller)의 인자(argument)로 전달되는 함수. 콜백 함수를 전달받은 함수는 이 콜백 함수를 호출(invoke)할 수 있다. caller는 조건(if)에 따라 콜백 함수의 실행 여부를 결정할 수도 있고, 심지어 여러 번(loop:for/while) 실행할 수도 있다. 특히 콜백 함수는 어떤 작업이 완료되었을 때 호출되는 경우가 많아서 답신 전화를 뜻하는 콜백이라는 이름이 붙여졌다.
커리 함수(Curry function) : 함수를 리턴하는 함수
고차함수 예시
- 다른 함수를 인자로 받는 경우
function double(num) {
return num * 2;
}
// double을 parameter에 넣어준다.
function doubleNum(func, num) {
return func(num);
}
// 함수 doubleNum은 다른 함수를 인자로 받는 고차 함수
// 함수 doubleNum의 첫 번째 인자 func에 함수가 들어올 경우
// 함수 func는 함수 doubleNum의 콜백 함수입니다.
// 아래와 같은 경우, 함수 double은 함수 doubleNum의 콜백 함수입니다.
let output = doubleNum(double, 4);
console.log(output); // -> 8
- 함수를 리턴하는 경우 (ex: closure)
function adder(added) {
return function (num) {
return num + added;
};
}
// 함수 adder는 다른 함수를 리턴하는 고차 함수.
// adder는 인자 한 개를 입력받아서 함수(익명 함수)를 리턴.
// 리턴되는 익명 함수는 인자 한 개를 받아서 added와 더한 값을 리턴.
// adder(5)는 함수이므로 함수 호출 연산자 '()'를 사용 가능
let output = adder(5)(3); // -> 8
console.log(output); // -> 8
// adder가 리턴하는 함수를 변수에 저장 가능
// javascript에서 함수는 일급 객체이기 때문
const add3 = adder(3);
output = add3(2);
console.log(output); // -> 5
- 함수를 인자로 받고, 함수를 리턴하는 경우
function double(num) {
return num * 2;
}
function doubleAdder(added, func) {
const doubled = func(added);
return function (num) {
return num + doubled;
};
}
// 함수 doubleAdder는 고차 함수.
// 함수 doubleAdder의 인자 func는 함수 doubleAdder의 콜백 함수.
// 함수 double은 함수 doubleAdder의 콜백으로 전달.
// doubleAdder(5, double)는 함수이므로 함수 호출 기호 '()'를 사용 가능
doubleAdder(5, double)(3); // -> 13
// doubleAdder가 리턴하는 함수를 변수에 저장할 수 있습니다. (일급 객체)
const addTwice3 = doubleAdder(3, double);
addTwice3(2); // --> 8
배열 내장 고차함수
- filter : 배열의 요소 중 함수를 통해 특정 조건을 만족하는 요소들만을 Boolean으로 걸러내어(filter) 새로운 배열을 만드는 메소드
배열의 각 요소가
특정 논리(함수)에 따르면, **사실(boolean)일 때**
따로 분류한다(filter).
let arr = [1, 2, 3, 4];
let output = arr.filter(짝수 판별 함수를 인자로 입력);
console.log(output); // ->> [2, 4]
arr = ['hello', 'code', 'states', 'happy', 'hacking'];
output = arr.filter(길이 5 이하 판별 함수를 인자로 입력)
console.log(output); // ->> ['hello', 'code', 'happy']
- map : 배열의 각 요소에 함수를 실행한 후의 요소들로 새로운 배열을 만드는 메소드
배열의 각 요소가
특정 논리(함수)에 의해
다른 요소로 지정(map) 된다.
- reduce : 배열의 초기값부터 배열의 끝까지 각 요소를 함수를 누적해서 실행 한 값
* 배열의 각 요소를
* 특정 응축 방법(함수)에 따라
* 원하는 하나의 형태로
* 응축한다(reduction)
function joinName(resultStr, user) {
resultStr = resultStr + user.name + ', ';
return resultStr;
}
let users = [
{ name: 'Tim', age: 40 },
{ name: 'Satya', age: 30 },
{ name: 'Sundar', age: 50 }
];
// reduce(함수, 문자열 초기값)
users.reduce(joinName, '');
사용 예시 : 더하기, 가장 큰 수 비교, 배열 형태의 다른 형태 등 다양한 사용사례가 있음
배열을 문자열로
function joinName(resultStr, user) {
resultStr = resultStr + user.name + ', ';
return resultStr;
}
let users = [
{ name: 'Tim', age: 40 },
{ name: 'Satya', age: 30 },
{ name: 'Sundar', age: 50 }
];
users.reduce(joinName, '');
// 초기값이 핵심
추상화(abstraction) :복잡한 어떤 것을 압축해서 핵심만 추출한 상태로 만드는 것.
추상화 = 생산성(productivity)의 향상
추상화의 관점에서 고차 함수가 갖는 이점 : 문제의 해결이 더 쉬워지는 것이 추상화의 이점입니다.
함수 = 값을 전달 받아 값을 리턴한다 = 값에 대한 복잡한 로직은 감추어져 있다 = 값 수준에서의 추상화
고차 함수는 이 추상화의 수준을 사고의 추상화 수준으로 끌어 올립니다.
고차함수 = 함수를 전달 받거나 함수를 리턴한다 = 사고(함수)에 대한 복잡한 로직은 감추어져 있다 = 사고 수준에서의 추상화
값 수준의 추상화: 단순히 값(value)을 전달 받아 처리하는 수준
사고의 추상화: 함수(사고의 묶음)를 전달 받아 처리하는 수준