본문 바로가기

Study/VanillaJS

[개념잡기] 함수형 프로그래밍 - (9) 마무리

[개념잡기] 함수형 프로그래밍 - (9) 마무리

_.js

지금까지 작성한 함수들을 정리해 보려고 한다.
기존에 작성한 코드는 const를 사용하여 함수를 선언하였는데 호이스팅 관련 문제로 var 로 변경하였다. (다음부터는 어떤 것을 사용할 때 알고 사용해야 겠다는 생각이 들었다.)

curry

함수의 평가시점을 늦춰줌. 2개의 인자가 채워지면 함수를 실행시킴

// curry
var _curry = (fn) => {
  return function (a, b) {
    return arguments.length == 2 ? fn(a,b) : b => fn(a, b)
  }
}

curryr

curry 의 두개의 인자를 따로 받을 때 처리되는 순서를 반대로 해줌

// curryr
var _curryr = (fn) => {
  return function (a, b) {
    return arguments.length == 2 ? fn(a,b) : b => fn(b, a)
  }
}

get

오브젝트에서 원하는 key를 가져옴

// get
var _get = _curryr((obj, key) => {
  return obj == null ? undefined : obj[key]
})

filter

특정 배열에서 원하는 값을 걸러냄

// filter
var _filter = _curryr((list, predi) => {
  var new_list = []
  _each(list, (val) => {
    if(predi(val)) {
      new_list.push(val)
    }
  })
  return new_list
})

map

특정 배열에서 원하는 값을 배열 형태로 반환

// map
var _map = _curryr((list, mapper) => {
  var new_list = []
  _each(list, (val) => {
    new_list.push(mapper(val))
  })
  return new_list
})

is object

해당 오브젝트의 type 검사

// is_object
var _is_object = (obj) => {
  return typeof(obj) == "object" && !!obj
}

keys

해당 오브젝트의 key 들을 리스트 형태로 반환

// keys
var _keys = (obj) => {
  return _is_object(obj) ? Object.keys(obj) : []
}

length

해당 배열의 길이를 반환

// length
var _length = _get("length")

each

해당 오브젝트 순회

// each
var _each = (list, iter) => {
  var keys = _keys(list)
  for(var i = 0, len = keys.length ; i < len; i++) {
    iter(list[keys[i]])
  }
}

reduce

해당 오브젝트를 순회하면서 함수에 값을 넣어 리턴값 반환

// reduce
var _reduce = function(list, iter, memo) {
  if(arguments.length == 2) {
    [memo, ...list] = list
  }
  _each(list, (val) => {
    memo = iter(memo, val)
  })
  return memo
}

pipe

함수 리스트를 받아 해당 순회하며 실행하는 함수 리턴

// pipe
var _pipe = function() {
  var fns = arguments
  return function(arg) {
    return _reduce(fns, function(arg, fn){
      return fn(arg)
    }, arg)
  }
}

go

pipe 즉시 실행함수

// go
var _go = function() {
  [arg, ...fns] = arguments
  return _pipe.apply(null, fns)(arg)
}

마무리

이렇게 _.js 의 기본 함수들이 마무리되었다. 함수와 함수가 하는 동작이 잘 연결되었는지 모르겠다. 만약 이상한 부분있으면 피드백바랍니다. 마지막으로 전체 소스이다.
_.js

// curry
var _curry = (fn) => {
  return function (a, b) {
    return arguments.length == 2 ? fn(a,b) : b => fn(a, b)
  }
}

// curryr
var _curryr = (fn) => {
  return function (a, b) {
    return arguments.length == 2 ? fn(a,b) : b => fn(b, a)
  }
}

// getters
var _get = _curryr((obj, key) => {
  return obj == null ? undefined : obj[key]
})

// filter
var _filter = _curryr((list, predi) => {
  var new_list = []
  _each(list, (val) => {
    if(predi(val)) {
      new_list.push(val)
    }
  })
  return new_list
})

// map
var _map = _curryr((list, mapper) => {
  var new_list = []
  _each(list, (val) => {
    new_list.push(mapper(val))
  })
  return new_list
})

// is_object
var _is_object = (obj) => {
  return typeof(obj) == "object" && !!obj
}

// keys
var _keys = (obj) => {
  return _is_object(obj) ? Object.keys(obj) : []
}

// length
var _length = _get("length")

// each
var _each = (list, iter) => {
  var keys = _keys(list)
  for(var i = 0, len = keys.length ; i < len; i++) {
    iter(list[keys[i]])
  }
}

// reduce
var _reduce = function(list, iter, memo) {
  if(arguments.length == 2) {
    [memo, ...list] = list
  }
  _each(list, (val) => {
    memo = iter(memo, val)
  })
  return memo
}

// pipe
var _pipe = function() {
  var fns = arguments
  return function(arg) {
    return _reduce(fns, function(arg, fn){
      return fn(arg)
    }, arg)
  }
}

// go
var _go = function() {
  [arg, ...fns] = arguments
  return _pipe.apply(null, fns)(arg)
}