Front-end/JavaScript

JS 클로저 3편 - HOF(고계함수, Higher Order Function)

파리외 개발자 2023. 1. 14. 18:58

HOF

hof는 여러 상황에 유동적으로 대응할 수 있는 일반화된 함수를 말한다.

기본적인 함수가 전편에서 설명했던 first class의 기능을 가질 때 HOF로 만들어질 수 있다.

로그인 기능을 예시로 HOF를 만들어 보겠다.

기본적인 형태의 함수

//HOF
function letAdamLogin() {
  let array = [];
  for (let i = 0; i < 100000; i++) {
    array.push(i);
  }
  return "Access Adam";
}

function letEvaLogin() {
  let array = [];
  for (let i = 0; i < 100000; i++) {
    array.push(i);
  }
  return "Access Eva";
}

letAdamLogin();
letEvaLogin();

각 함수의 array와 반복문 부분은 로그인 로직을 예시로 작성한 것이며 큰 의미는 없다.

위 처럼 로그인 함수를 작성하면 각 사용자에 따라 함수를 제각각 만들어줘야 한다.

함수의 인자를 이용

function letUserLogin(user) {
  let array = [];
  for (let i = 0; i < 100000; i++) {
    array.push(i);
  }
  return "Access" + user;
}

letUserLogin("Adam");
letUserLogin("Eva");

사용자의 이름을 인자로 받는다면 하나의 함수로 모든 사용자에 대해 대응할 수 있다.

여기서 만약 로그인이 되고 추가의 작업이 더 필요할 때, 리턴 부분을 일반화시킬 수 있다.

예를 들어 로그인된 사용자의 아이디를 GNB에 표시를 한다거나,

함수를 리턴

//함수에 어떤 데이터를 전달할 지 정할 수 있다.
const giveAccessTo = (name) => "Access to " + name;

function letUserLogin(user) {
  let array = [];
  for (let i = 0; i < 100000; i++) {
    array.push(i);
  }
  return giveAccessTo(user);
}

letUserLogin("Adam");
letUserLogin("Eva");

로그인하는 사용자에 따라 인자를 다르게 전달하여 로그인 후 로직을 진행할 수 있다.

그런데 로그인 로직에 일반 사용자뿐 아니라 관리자 로그인이 필요한 경우가 있을 수 있다.

//사용자의 타입에 따라 함수의 내용이 달라질 때
const giveAccessTo = (name) => "Access to " + name;

function letUserLogin(user) {
  let array = [];
  for (let i = 0; i < 100000; i++) {
    array.push(i);
  }
  return giveAccessTo(user);
}

function letAdminLogin(admin) {
  let array = [];
  for (let i = 0; i < 5000000; i++) {
    array.push(i);
  }
  return giveAccessTo(admin);
}

letUserLogin("Adam");
letAdminLogin("SEO");

로그인 로직의 반복문 횟수가 더 늘어나는 것 때문에 함수를 새로 하나 더 만들게 된다.

이는 아래의 방법으로 일반화가 가능하다.

함수를 인자로 전달

//사용자의 타입에 따라 함수의 내용이 달라질 때
const giveAccessTo = (name) => "Access to " + name;

function authenticate(verify) {
  let array = [];
  for (let i = 0; i < verify; i++) {
    array.push(i);
  }
  return true;
}

function letPerson(person, fn) {
  if (person.level === "admin") {
    fn(500000);
  } else if (person.level === "user") {
    fn(100000);
  }
  return giveAccessTo(person.name);
}

letPerson({ level: "user", name: "Adam" }, authenticate);
letPerson({ level: "admin", name: "SEO" }, authenticate);

letPerson로그인 함수는 두 번째 인자로 authenticate함수를 받아서

사용자의 타입에 따라 authenticate함수에 인자를 다르게 지정하여 로그인 로직을 작동시킨다.

이렇게 함수를 인자로 전달할 시 인증외의 다른 행동 또한 해당함수로 일반화시킬 수 있다.

const giveAccessTo = (name) => "Access to " + name;

function masage(person) {
  return "Hi" + person.name;
}

function authenticate(person, verify) {
  let array = [];
  for (let i = 0; i < verify; i++) {
    array.push(i);
  }
  return giveAccessTo(person.name);
}

function letPerson(person, fn) {
  if (person.level === "admin") {
    return fn(person, 500000);
  } else if (person.level === "user") {
    return fn(person, 100000);
  }
}

letPerson({ level: "user", name: "Adam" }, authenticate);
letPerson({ level: "admin", name: "SEO" }, authenticate);
letPerson({ level: "user", name: "Eva" }, masage);

HOF를 사용하면 letPerson함수는 사용자의 행동을 fn인자로 받으며 

사용자의 level에 따라 행동에 다른 인자를 전달할 수 있게된다.

이렇게 HOF를 사용하면 행위를 일반화하여 적은 코드로 구조화된 로직을 만들 수 있다.