함수가 함수를 매개변수로 받거나, 함수 자체가 또다른 함수를 반환하는 함수를 의미한다. 고차함수는, 일급함수에 내재된 유형이며, 고차함수에 대해 제대로 알기 위해서는 함수형 프로그래밍에 대해 먼저 공부할 필요가 있다.
자바스크립트에는 이미 많은 고차함수 기반의 메서드가 존재한다. 주어진 값을 기반으로 콜백함수의 연산을 통해 새로운 결과값을 반환한다. 대표적으로, map()
함수는 배열의 각 요소에 해당 함수연산을 적용하여 새로운 배열을 반환해준다. 그 말은 map()
은 구현한 함수를 매개변수로 재사용하여, 새로운 값을 반환하는 고차함수라고 표현할 수 있다.
const arr = [1,2,3,4];
const newArr = arr.map((x)=> x*x));
console.log(newArr) // [1,4,9,16];
function square(x) {
return x*x;
}
const arr = [1,2,3,4];
const newArr = arr.map(squre);
console.log(newArr) // [1,4,9,16];
일급함수의 내재된 유형으로써, 주어진 데이터를 기반으로 새로운 결과값을 반환한다는 점에서 협업 시 데이터 변질을 최소화할 수 있다는 장점이 있다. 위의 코드에서도 forEach()
를 통해 가능한 일을 map()
으로 진행한 것 역시 일급함수의 특징을 살려 사이드 이펙트를 최소화하기 위함이다. 기존의 데이터를 다시 재사용하여 새로운 결과를 반환하도록 유도하는 확장성이 증가한다.
그 외에도 연산을 진행하는 함수와 부모가 되는 함수의 영역을 나눈다는 점에서 코드가 간결해지고, 다양한 접근 시도가 가능해진다. 예를들어 부모 함수 A
와 A
의 인자 함수인 B,C,D
가 있다면, AB,AC,AD
등의 조합을 통해 A
를 재사용하면서도 동시에 다른 결과를 맞이하도록 할 수 있다.
function A (num, fn) {
return fn(num);
}
function B (num) {
return num+num;
}
function C (num) {
return num+num+num;
}
function D (num) {
return num.toString(16);
}
console.log(A(1,B)); // 2
console.log(A(2,C)); // 6
console.log(A(18,D)); // 12
컴포넌트를 인자로 받아 새로운 컴포넌트를 반환하는 함수를 말한다. 고차함수와 유사(동일)하게, HOC 역시 컴포넌트를 재사용함과 동시에, 다양한 방식의 새로운 결과를 가져오도록 유도한다. 예를들어, Login 컴포넌트 자체를 상태값을 관리하는 영역과 상태를 받아 요소를 반환하는 영역으로 나누어, 요소 반환 영역은 그대로 재사용하면서, 상태값 로직을 다양하고 시도해보는 것이 가능하다.
const Login = () => (
const [isLoggedIn, setIsLoggedIn] = useState(false);
return (<div>
{isLoggedIn ? (
<h1>You are logged in</h1>
) : (
<h1>You are not logged in</h1>
)}
<button onClick={() => setIsLoggedIn(!isLoggedIn)}>
{isLoggedIn ? "Logout" : "Login"}
</button>
</div>
</div>)
))
const withLogin = (Component) => {
return (props) => {
const [isLoggedIn, setIsLoggedIn] = useState(false);
// 다양한 로직을 추가해보자.
// 자식에게 현재 로그인 상태를 반환
return (
<Component
{...props}
isLoggedIn={isLoggedIn}
setIsLoggedIn={setIsLoggedIn}
/>
);
};
};
const withValidation = ({Component,onValid,id,password}) => {
return (props) => {
const [isLoggedIn, setIsLoggedIn] = useState(false);
//valid 로직 추가한다면?
if(!onValid(id,password)) {
..
..
return <ErrorComponent />
}
return (
<Component
{...props}
isLoggedIn={isLoggedIn}
setIsLoggedIn={setIsLoggedIn}
/>
);
};
};
...
...
const Login = withLogin(({ isLoggedIn, setIsLoggedIn }) => (
<div>
{isLoggedIn ? (
<h1>You are logged in</h1>
) : (
<h1>You are not logged in</h1>
)}
<button onClick={() => setIsLoggedIn(!isLoggedIn)}>
{isLoggedIn ? "Logout" : "Login"}
</button>
</div>
))