함수형 프로그래밍 D2

nearworld·2023년 1월 9일
0
// 객체 지향
duck.moveLeft();
dog.moveLeft();
duck.moveRight();
dog.moveRight();

// 함수형
moveLeft(duck);
moveRight(dog);

객체지향과 함수형 프로그래밍의 차이는 객체를 기준으로 하냐 함수를 기준으로 프로그램이 동작하느냐...

객체지향 프로그래밍에서는 객체 인스턴스의 원본인 클래스에 메서드들을 정의해서 해당 클래스의 인스턴스 객체들에 딸린 메서드들이 같은 동작을 한다.

그러나 함수형 프로그래밍에서는 함수에 맞게 데이터 (객체)를 입력해줘야한다.

함수형 프로그래밍의 첫 실전 예제 함수 _filter 함수를 만들어보자.

function _filter(users) {
  let temp_list = [];
  for (let i = 0; i < users.length; i++) {
    if (users[i].age >= 10) {
      temp_list.push(users);
    }
  }
  return temp_list;
}

위 함수는 users라는 배열을 인자로 받고 배열을 순회하며 배열 요소들인 객체들의 나이가 10 이상인 것들만 걸러내어 temp_list 배열에 푸쉬하고 있다.

위 filter 함수는 age 프로퍼티를 가지는 특정 객체에 의존적인 로직을 사용하고 있다.
함수를 만들 때, 그 함수가 한 객체에만 의존적으로 작동하기 보다는 범용적으로 여러 데이터를 필터링 할 수 있는게 더 생산적일 것이다.

if (users[i].age >= 10) {
  temp_list.push(users);
}

filter 함수에 제한적인 사용을 주는 로직이 바로 이 부분이다.
고로 이 if 조건문이 변경되어야 할 것이다..

위 조건문의 결과를 리턴하는 함수를 만들어 if문에 박아보자.

function _filter(users, predicate) {
  let temp_list = [];
  for (let i = 0; i < users.length; i++) {
    if (predicate(users)) {
      temp_list.push(users);
    }
  }
  return temp_list;
}

_filter(users, function(users) {return users.age >= 10;});

여기서 대단한 변화가 생긴다.. 바로 filter함수 내부의 로직에 유연성이 생긴것이다..
유연성이 생길 수 있는 것은 filter함수 내의 조건문이 외부에서 들어오게 되면서다.
즉, 외부에서 들어오는 조건문에 의존을 하게 되는 것이다.
외부에서 들어오는 조건문은 아주 다양한 종류일 수 있다. 실제 코드 예시를 보자.

_filter(users, function(users) {return users.age >= 10;});
_filter([1, 2, 3, 4], function(users) {return users >= 2;});
_filter([100, 200, 300, 400], function(users) {return users >= 100;});

이제 _filter 함수는 아주 다양한 종류의 데이터를 인자로 받아 여러 종류의 필터링 기능을 갖출 수 있게 되었다.

이제 _filter 함수가 유연성을 갖게 되었으니 파라미터 이름도 바꿔주자..

function _filter(list, predicate) {
  let temp_list = [];
  for (let i = 0; i < list.length; i++) {
    if (predicate(list[i])) {
      temp_list.push(list[i]);
    }
  }
  return temp_list;
}

console.log(
    _filter([1, 2, 3, 4, 5], function (data) {return data > 3;}))
const users = [
  {
    id: 1,
    name: 'boo',
    age: 10
  },
  {
    id: 2,
    name: 'baa',
    age: 20
  },
  {
    id: 3,
    name: 'bee',
    age: 30
  }
];

users라는 데이터를 함수형 프로그래밍 패러다임을 이용해 다뤄보자.

function _filter(list, predicate) {
  let temp_list = [];
  for (let i = 0; i < list.length; i++) {
    if (predicate(list[i])) {
      temp_list.push(list[i]);
    }
  }
  return temp_list;
}

const over_20 = _filter(users, function (user) {return user.age >= 20;});

users 데이터에서 age가 20이상인 객체만 담긴 배열을 over_20에 할당했다.
이제 나이가 20이상인 유저만 추출했으니 이 나이가 20이상인 유저들의 이름을 뽑아보자.

function _map(list, mapper) {
  let temp_list = [];
  for (let i = 0; i < list.length; i++) {
    temp_list.push(mapper(list[i]));
  }
}

const names = _map(over_20, function (user) {return user.name;});

_map 함수를 통해 나이가 20인 유저들의 이름만 추출했다.
이름이 _map인 이유는 나이와 이름을 맵핑했다는 의미같다.

2개의 함수를 만들었는데.. _filter, _map.
이 두 함수를 들여다보면.. 중복되는 부분이 보인다. 바로 반복문.
이 반복문도 함수로 만들어보자. 그럼 매번 저 반복문을 쓸 필요없이 반복문 기능을 하는 함수만 갖다 쓰면 되기때문에 코드 생산성이 증가할테다..!

function _each(list, iter) {
  for (let i = 0; i < list.length; i++) {
    iter(list[i]);
  }
}

이제 _filter, _map 함수 내부에 있는 반복문을 _each 로 대체해보자!

function _filter(list, predicate) {
  let temp_list = [];
  _each(list, function (item) {
    if (predicate(item)) temp_list.push(item);
  });
  return temp_list;
}

const over_20 = _filter(users, function (user) {return user.age >= 20;});

function _map(list, mapper) {
  let temp_list = [];
  _each(list, function (item) {
    temp_list.push(mapper(item));
  });
  return temp_list;
}

const names = _map(over_20, function (user) {return user.name;});
profile
깃허브: https://github.com/nearworld

0개의 댓글