JavaScript로 알아보는 함수형 프로그래밍 1 - filter, map

본 포스트는 인프런 강의를 듣고 강의 내용을 정리한 포스트입니다!

함수형 프로그래밍이란?

함수형 프로그래밍은 순수 함수들을 이용해 조합성을 강조하는 프로그래밍 패러다임입니다.

  • 순수 함수 특)

동일한 인자를 넣으면 동일한 결과를 리턴한다

어느 시점에 함수를 호출하는지는 중요하지 않다


함수형 프로그래밍과 자주 비교되는 것으로 객체지향 프로그래밍이 있습니다.

객체지향 프로그래밍은 데이터(객체) 기준으로 설계해 나가고, 함수형 프로그래밍은 함수를 기준으로 설계해 나간다는 차이가 있습니다.

함수형 프로그래밍에서는 함수를 먼저 만들고, 함수에 맞는 데이터를 구성한다는 것이 가장 큰 차이가 되겠습니다.

// 데이터 기준
mengkki.moveLeft()
mengkki.moveRight()

//함수 기준
moveLeft(mengkki)
moveRight(mengkki)

함수형으로 전환하기 - filter, map

let users = [
  { id: 1, name: 'mengkki', age: 25 },
  { id: 2, name: 'hello', age: 50 },
  { id: 3, name: 'world', age: 34 },
  { id: 4, name: 'momo', age: 22 },
  { id: 5, name: 'baby', age: 3 },
  { id: 6, name: 'hemzzi', age: 22 },
  { id: 7, name: 'dumbo', age: 26 },
]

위와 같은 users 라는 리스트가 있습니다.

이 중에서 나이가 30세 이상인 유저들을 뽑아오겠습니다.

let tmp_users = []
for (let i = 0; i < users.length; i++) {
  if (users[i].age >= 30) tmp_users.push(users[i])
}
/*
[
  { id: 2, name: 'hello', age: 50 },
  { id: 3, name: 'world', age: 34 }
] */

이제 나이가 30세 이상인 유저들의 이름을 뽑아오겠습니다.

let names = []
for (let i = 0; i < tmp_users.length; i++) {
  names.push(tmp_users[i].name)
}
// [ 'hello', 'world' ]

위 기능들을 함수형 프로그래밍으로 구현해보겠습니다.

filter

먼저 필터링 하는 기능입니다.

function _filter(list, predi) {
  //   predi는 함수.
  let new_list = []
  for (let i = 0; i < list.length; i++) {
    if (predi(list[i])) new_list.push(list[i])
  }
  return new_list
}

console.log(_filter(users, user => user.age >= 30))
/*
[
  { id: 2, name: 'hello', age: 50 },
  { id: 3, name: 'world', age: 34 }
] */

_filter라는 함수 안에 필터링 할 리스트와 어떤 기준으로 필터링을 할지 결정해주는 predi라는 함수를 인자로 넘겨줌으로써

_filter 함수를 호출 할 때 마다 그 때에 맞는 조건을 넘겨서 사용 할 수 있도록

재사용성을 높힌 필터링 함수가 만들어졌습니다.

console.log(_filter([1, 2, 3, 4, 5, 6], num => num < 4))
//[ 1, 2, 3 ]

첫번째 인자로 users가 아니라 다른 리스트가 들어가도 정상적으로 작동하는 모습을 보여줍니다.

map

let over_30 = _filter(users, user => user.age >= 30)

function _map(list, mapper) {
  //무엇을 푸시할것인가를 mapper라는 함수에게 위임함
  let new_list = []
  for (let i = 0; i < list.length; i++) {
    new_list.push(mapper(list[i]))
  }
  return new_list
}
//안에 들어올 데이터의 형식이 어떻게 생겼는지 전혀 보이지 않음.

let over30_names = _map(over_30, item => item.name) // [ 'hello', 'world' ]

비슷한 방법으로 map 함수도 구현해보았습니다.

mapper함수에게 어떤 데이터를 push 할 지를 위임하고,

_map 함수를 호출할 때에 mapper 함수를 결정해줍니다.

console.log(_map([1, 2, 3, 4], item => item * item))
// [ 1, 4, 9, 16 ]

마찬가지로 users가 아닌 데이터에도 대응하는 모습을 보여줍니다.

이제 위의 _filter와 _map을 한번에 사용해서

나이가 30 이상인 users의 name을 뽑아보도록 하겠습니다.

_map(
  _filter(users, user => user.age >= 30),
  user => user.name
)
//[ 'hello', 'world' ]

_map의 첫번째 인자로 _filter 함수의 실행결과로 나온 배열을 넣어주고,

두번째 인자로 user.name을 리턴하는 함수를 넣어줌으로써

위의 코드가 이렇게 간결해졌습니다!

신묘한 함수형 프로그래밍의 세상… +_+


Written by@Mengkki
common fangirl

GitHub