고차함수,
이름도 어려운 고차함수!
오늘은 이 녀석을 배워보자!
함수를 인자(argument)로 받을 수 있고,
함수의 형태로 리턴할 수 있는 함수이다.
이 때 다른 함수에 인자로 전달되는 함수는
콜백 함수라고 부른다.
다른 함수를 인자로 받는 경우
function add(num) {
return num + 2;
}
function addNum(func, num) {
return func(num);
}
위와 같이 num에 2를 더해주는 'add' 함수가 있고,
그 'add' 함수와 num을 인자로 받는 'addNum' 함수가 있다.
이 때 addNum(add, 4)
를 입력하면
'addNum' 함수의 첫번째 인자에 'add' 함수가 전달되고,
return값에 의해 4 + 2 = 6이 결과로 나오게 된다.
함수를 리턴하는 경우
function adder(num1) {
return function add(num2) {
return num1 + num2;
}
}
위와 같은 코드가 있다.
이 상태에서 'adder' 함수를 실행시켜도
'add' 함수만 리턴하게 된다.
그래서 adder(1)(2);
// 3
또는
let add5 = adder(5)
위와 같이 함수 자체를 선언해주고,
add5(3)
// 8
이처럼 함수를 호출할 수 있다.
함수를 인자로 받고, 함수를 리턴하는 경우
function double(num) {
return num * 2;
}
function doubleAdder(added, func) {
const doubled = func(added);
return function (num) {
return num + doubled;
}
}
num에 2를 곱해주는 'double' 함수가 있고,
added와 함수를 인자로 받는 함수 안에는
인자로 받은 함수에 added를 전달해 실행시키는 함수를
doubled로 선언했다.
여기서 num을 인자로 받는 익명의 함수를 실행하고,
리턴값으로 인자로 전달받은 num과 선언해둔 doubled를
더해주게 되면,
num에 2를 곱해주는 숫자에 num을 더한 값이 리턴된다.
JavaScript에는 기본적으로 내장되어 있는
고차함수들이 있다.
이 고마운 Method들을 알아보도록 하자.
filter()
-> 배열 내의 특정한 조건을 만족하는 요소를 걸러낸다.
(원본 배열에 변화를 주지 않는다)
[1, 2, 3] 이라는 배열이 있고, 이 배열에서 2라는 요소를 걸러내고 싶을 때는
[1, 2, 3].filter(arr => arr === 2); // [2].
[1, 2, 3].filter(arr => arr !== 2); // [1, 3].
위와 같이 필터링할 수 있다.
화살표 함수를 사용하지 않는 방법도 있긴하다.
[1, 2, 3].filter( function (arr) {
return arr === 2;
}); // [2]
위와 같이 나타낼 수 있다.
filter를 이용한 배열에서 짝수만 뽑아내기
let arr = [1, 2, 3, 4, 5, 6, 7, 8];
arr.filter(num => num % 2 === 0);
// [2, 4, 6, 8]
map()
-> 배열 내의 요소를 함수에 조건에 맞추어 바꿔준다.
(원본 배열에 변화를 주지 않는다)
[1, 2, 3] 이라는 배열이 있고, 이 요소에 전부 2를 곱해주고 싶을 때는
[1, 2, 3].map(num => num * 2); // [2, 4, 6]
전부 10을 더해주고 싶을 때는
[1, 2, 3].map(num => num + 10); // [11, 12, 13]
위와 같이 바꿔줄 수 있다.
모든 요소를 원하는 요소로 바꿔주고 싶을 때는
[1, 2, 3].map(num => 5); // [5, 5, 5]
우와 같이 입력하면 된다.
map을 이용해 전체에 5 곱해주기
let arr = [1, 2, 3, 4];
arr.map(num => num * 5);
// [5, 10, 15, 20]
reduce
-> 만능이다. 전부 합쳐버린다. 누적시킨다. 이걸로 map도 할 수 있고,
filter, sort도 할 수 있다.
[1, 2, 3] 이라는 배열이 있고, 이 수를 전부 더해주고 싶을 때는
[1, 2, 3].reduce((num1, num2) => num1 + num2);
// 6 (1 + 2 + 3)
위와 같이 나타낼 수 있다. 함수 끝에 시작점을 정해줄 수 있다.
예를 들어, 아래와 같다.
[1, 2, 3].reduce((num1, num2) => num1 + num2, 5);
// 11 (5 + 1 + 2 + 3)
reduce를 이용해 전체를 곱해주기
let arr = [1, 2, 3];
arr.reduce((num1, num2) => num1 * num2);
// 6 (1 * 2 * 3)
지금까지 알아본 내장 고차함수의 3가지 Method들을 정말 자주
이용하게 된다. 아주 잘 알아두자.
절차형 프로그래밍
어떻게?
절차형 프로그래밍은
내가 원하는 결과를 코드로 달성해 나가는 과정을 중점에 둔 방식이다.
function add2(arr) {
let result = [];
for (let i = 0; i < arr.length; i++) {
result.push(arr[i] + 2)
}
return result;
}
위 코드와 같이 배열의 각 요소에 2를 더해주기 위해
반복문을 사용해 배열 요소에 전부 접근한 뒤 계산해주는 방식을 사용한다.
선언형 프로그래밍
무엇을?
선언형 프로그래밍은 '필요한 것이 무엇인지' 를 작성하는것에
중점을 둔 방식이다.
절차형 프로그래밍 방식에서 했던것과 같은 코드를
선언형 프로그래밍 방식으로 나타내면 아래와 같이 나타낼 수 있다.
function add2(arr) {
return arr.map(arr => arr + 2);
}
위 코드는 map()이 작동하는 방식을 가시화해서
코드를 짜는게 아닌 내장 고차함수를 이용함으로써
절차형 프로그래밍 방식이 추상화된 것이다.
가시적으로 보이는게 아니라 생각하기는 어렵지만
더 높은 차원에서 프로그래밍을 할 수 있다.