Skip to content

unfold

js
const unfold = (iteratorFn, seedValue, list = []) => {
  const either = iteratorFn(seedValue);
  if (either) {
    const [result, nextSeedValue] = either;
    return unfold(iteratorFn, nextSeedValue, [...list, result])
  } else {
    return list;
  }
};

const fn = n => {
  return n > 50
    ? false
    : [-n, n + 10]
};

console.log(unfold(fn, 10));
//=> [-10, -20, -30, -40, -50]
console.log(unfold(fn, 60));
//=> []

always

js
const always = v => _ => v

const five = always(5)
console.log(five()) // 5

boolean

ts
export const toBool = function(value: any): boolean {
  return Boolean(value)
}

export const not = function(value: any): boolean {
  return !toBool(value)
}

curry

js
const curry1 = fn => arg => fn(arg)

parseInt('11') // => 11
parseInt('11', 2) // => 3

['11', '11', '11'].map(parseInt)
// => [11, NaN, 3]

['11', '11', '11'].map(curry1(parseInt))
// => [11, 11, 11]

const curry2 = fn => arg1 => arg2 => fn(arg1, arg2)

const map = curry2((fn, arr) => arr.map(fn))
map(v => v * 10)([1, 2, 3])
// [10, 20, 30]

is-same

ts
export const isSame = function<T>(src: T) {
  return (target: T): boolean => Object.is(src, target)
}

console.log(isSame('foo')('foo') ===true)
console.log(isSame(window)(window) ===true)

console.log(isSame('foo')('bar') ===false)
console.log(isSame([])([]) ===false)

var test = { a: 1 }
console.log(isSame(test)(test) ===true)

console.log(isSame(null)(null) ===true)

console.log(isSame(0)(-0) === false)
console.log(isSame(-0)(-0) === true)
console.log(isSame(NaN)(0/0) ===true)

memoize

js
const memoize = (fn) => {
  const cache = {}
  return (n) => {
    if (!cache[n]) {
      cache[n] = fn(n)
    }
    return cache[n]
  }
}

once

ts
type OnceCallback<T> = (value?: T) => void
export const once = function<T>(callback: OnceCallback<T>): OnceCallback<T> {
  let isCalled = false
  return function(value?: T): void {
    if (!isCalled) {
      isCalled = true
      callback(value)
    }
  }
}

const onceFn = once(console.log)
onceFn('test')
onceFn('test')
onceFn('test')
onceFn('test')

partial

js
const partial = (fn, ...arg1) => (...arg2) => fn(...arg1, ...arg2)

const add = (a, b) => a + b
const add10 = partial(add, 10)

add10(5) // 15

const addAll = (a, b, c, d) => a + b + c + d
const addTwo = partial(addAll, 10, 10)

addTwo(5, 5) // 30

pipe

js
const pipe = (fn, ...fns) => (...arg) => {
  return fns.reduce((acc, fn) => fn(acc), fn(...arg))
}

pipe(
  v => v * 10,
  v => `${v}%`,
  console.log
)(10)
// 100%

plucker

js
const plucker = field => obj => (obj && obj[field])

const best = { title: '인피니티워', author: 'Peter' }
const books = [{title: '스파이더맨'}, {title: '아이언맨'}, {title: '토르'}]

const extractTitle = plucker('title')
const extractThird = plucker(2)

extractTitle(best) // '인피니티워'
extractThird(books) // {title: '토르'}

range

js
const range = length => Array.from({length}, (_, i) => i)

module.exports = range

tab

ts
export const tap = function<T>(callback: (value: T) => void) {
  return (value: T): T => {
    callback(value)
    return value
  }
}

fp

js
const range = require('./range')
const chunk = require('./chunk')
const each = iter => (list) => {
  for (let i = 0, len = list.length; i < len; i++) {
    iter(list[i], i, list, len)
  }
  return list
}
const loop = iter => len => {
  for (let i = 0; i < len; i++) {
    iter(i, len)
  }
  return len
}
const map = iter => list => {
  const newList = []
  each(item => {
    newList.push(iter(item))
  })(list)
  return newList
}
const filter = iter => list => {
  const newList = []
  each(item => {
    if (iter(item)) {
      newList.push(item)
    }
  })(list)
  return newList
}
const find = iter => list => {
  for (let i = 0, len = list.length; i < len; i++) {
    if (iter(list[i], i, list)) return list[i]
  }
  return null
}
const findIndex = iter => list => {
  for (let i = 0, len = list.length; i < len; i++) {
    if (iter(list[i], i, list)) return i
  }
  return -1
}
const reduce = (init, iter) => list => {
  each((item) => {
    init = iter(init, item)
  })(list)
  return init
}
const pipe = (...fns) => res => {
  return reduce(res, (res, fn) => fn(res))(fns)
}
const divEq = (...fns) => val => { // Divided Equal
  each((fn) => fn(val))(fns)
  return val
}
const isUndefined = (obj) => typeof obj === 'undefined'
const negate = v => !v
const clone = (obj) => {
  if (typeof (obj) !== 'object') {
    return obj
  }

  var copiedObj = obj.constructor()

  for (var attr in obj) {
    if (obj.hasOwnProperty(attr)) {
      copiedObj[attr] = clone(obj[attr])
    }
  }

  return copiedObj
}
const merge = (defaultOptions, _options) => {
  var newOptions = clone(_options)

  for (var keyName in defaultOptions) {
    if (isUndefined(newOptions[keyName])) {
      newOptions[keyName] = defaultOptions[keyName]
    }
  }

  return newOptions
}

module.exports = {
  each,
  loop,
  map,
  filter,
  find,
  findIndex,
  reduce,
  pipe,
  divEq,
  isUndefined,
  negate,
  clone,
  merge,
  range,
  chunk
}
js
const reduce = (arr, iter, def) => arr.reduce(iter, def)

const arr = []
for (let char of '12345') {
  arr.push(char)
}
console.log(arr) // => ['1','2','3','4','5']

const arr2 = reduce([...'12345'], (acc, val) => {
  acc.push(val)
  return acc
}, [])

console.log(arr2)