YOU MIGHT NOT NEED LODASH

Just to be clear: you should probably use Lodash – just make sure you import the bits you need, not the whole library to use one method.

Lodash is a great library, well crafted, battle tested and with a strong team. This page, on the other hand, is a mere exercise to explore how to achieve similar functionalities in plain js: sometimes it’s nice to understand the nitty gritty of how stuff works behind the hood.

Some of the implementations have been simplified to make them more digestible, and they might miss edge cases covered in the original Lodash version.

There are also some methods yet to be ported; if you want to help please contribute on github.

array

chunk

lodash

// https://lodash.com/docs/#chunk
import { chunk } from 'lodash'

chunk(['a', 'b', 'c', 'd', 'e', 'f', 'g'])
// => [['a'], ['b'], ['c'], ['d'], ['e'], ['f'], ['g']]

chunk(['a', 'b', 'c', 'd', 'e', 'f', 'g'], 3)
// => [['a', 'b', 'c'], ['d', 'e', 'f'], ['g']]

chunk(['a', 'b', 'c', 'd', 'e', 'f', 'g'], 0)
// => []

chunk(['a', 'b', 'c', 'd', 'e', 'f', 'g'], -1)
// => []

plain js

const chunk = (arr, chunkSize = 1, cache = []) => {
  const tmp = [...arr]
  if (chunkSize <= 0) return cache
  while (tmp.length) cache.push(tmp.splice(0, chunkSize))
  return cache
}

chunk(['a', 'b', 'c', 'd', 'e', 'f', 'g'])
// => [['a'], ['b'], ['c'], ['d'], ['e'], ['f'], ['g']]

chunk(['a', 'b', 'c', 'd', 'e', 'f', 'g'], 3)
// => [['a', 'b', 'c'], ['d', 'e', 'f'], ['g']]

chunk(['a', 'b', 'c', 'd', 'e', 'f', 'g'], 0)
// => []

chunk(['a', 'b', 'c', 'd', 'e', 'f', 'g'], -1)
// => []
Resources: Spread syntax Array#splice

compact

lodash

// https://lodash.com/docs/#compact
import { compact } from 'lodash'

compact([0, 1, 2])
// => [1, 2]

plain js

[0, 1, 2].filter(x => !!x)
// => [1, 2]
Resources: Array#filter Source

concat

lodash

// https://lodash.com/docs/#concat
import { concat } from 'lodash'

concat([1], 2, [3], [[4]])
// => [1, 2, 3, [4]]

plain js

[1].concat(2, [3], [[4]])
// => [1, 2, 3, [4]]
Resources: Array#concat Source

difference

lodash

// https://lodash.com/docs/#difference
import { difference } from 'lodash'

difference([2, 1], [3, 2])
// => [1]

plain js

[2, 1].filter(x => ![3, 2].includes(x))
// => [1]
Resources: Spread syntax Source

differenceBy

lodash

// https://lodash.com/docs/#differenceBy
import { differenceBy } from 'lodash'

differenceBy([2.1, 1.2], [2.3, 3.4], Math.floor)
// => [1.2]

// The `_.property` iteratee shorthand.
differenceBy([{ x: 2 }, { x: 1 }], [{ x: 1 }], 'x')
// => [{ 'x': 2 }]

plain js

[2.1, 1.2].filter(
  a => ![2.3, 3.4].map(Math.floor).includes(Math.floor(a))
)
// => [1.2]

// The `_.property` iteratee shorthand.
[{ x: 2 }, { x: 1 }].filter(
  a => ![{ x: 1 }].map(b => b.x).includes(a.x)
)
// => [{ 'x': 2 }]
Resources: Spread syntax

drop

lodash

// https://lodash.com/docs/#drop
import { drop } from 'lodash'

drop([1, 2, 3])
// => [2, 3]

drop([1, 2, 3], 2)
// => [3]

drop([1, 2, 3], 5)
// => []

drop([1, 2, 3], 0)
// => [1, 2, 3]

plain js

const drop = (arr, n = 1) => arr.slice(n)

drop([1, 2, 3])
// => [2, 3]

drop([1, 2, 3], 2)
// => [3]

drop([1, 2, 3], 5)
// => []

drop([1, 2, 3], 0)
// => [1, 2, 3]
Resources: Default parameters Array#slice

dropRight

lodash

// https://lodash.com/docs/#dropRight
import { dropRight } from 'lodash'

dropRight([1, 2, 3])
// => [1, 2]

dropRight([1, 2, 3], 2)
// => [1]

dropRight([1, 2, 3], 5)
// => []

dropRight([1, 2, 3], 0)
// => [1, 2, 3]

plain js

const dropRight = (arr, n = 1) => arr.slice(0, -n || arr.length)

dropRight([1, 2, 3])
// => [1, 2]

dropRight([1, 2, 3], 2)
// => [1]

dropRight([1, 2, 3], 5)
// => []

dropRight([1, 2, 3], 0)
// => [1, 2, 3]
Resources: Default parameters Array#slice

fill

lodash

// https://lodash.com/docs/#fill
import { fill } from 'lodash'

fill([1, 2, 3], 'a')
// => ['a', 'a', 'a']

fill(Array(3), 2)
// => [2, 2, 2]

fill([4, 6, 8, 10], '*', 1, 3)
// => [4, '*', '*', 10]

plain js

[1, 2, 3].fill('a')
// => ['a', 'a', 'a']

Array(3).fill(2)
// => [2, 2, 2]

[4, 6, 8, 10].fill('*', 1, 3)
// => [4, '*', '*', 10]
Resources: Array#find Source

findIndex

lodash

// https://lodash.com/docs/#findIndex
import { findIndex } from 'lodash'

const users = [
  { user: 'barney', age: 36, active: true },
  { user: 'fred', age: 40, active: false },
  { user: 'pebbles', age: 1, active: true },
]

findIndex(users, o => o.age >= 40)
// => 1

plain js

const users = [
  { user: 'barney', age: 36, active: true },
  { user: 'fred', age: 40, active: false },
  { user: 'pebbles', age: 1, active: true },
]

users.findIndex(o => o.age >= 40)
// => 1
Resources: Array#findIndex Source

findLastIndex

lodash

// https://lodash.com/docs/#findLastIndex
import { findLastIndex } from 'lodash'

const users = [
  { user: 'barney', active: true },
  { user: 'fred', active: false },
  { user: 'pebbles', active: false },
]

findLastIndex(users, o => !o.active)
// => 2

findLastIndex(users, o => !o.user)
// => -1

plain js

const findLastIndex = (arr, func) => {
  const reverseIdx = [...arr].reverse().findIndex(func)
  return reverseIdx === -1 ? reverseIdx : arr.length - (reverseIdx + 1)
}

const users = [
  { user: 'barney', active: true },
  { user: 'fred', active: false },
  { user: 'pebbles', active: false },
]

findLastIndex(users, o => !o.active)
// => 2

findLastIndex(users, o => !o.user)
// => -1
Resources: Array#reverse Array#findIndex

flatten

lodash

// https://lodash.com/docs/#flatten
import { flatten } from 'lodash'

flatten([1, [2, [3, [4]], 5]])
// => [1, 2, [3, [4]], 5]

plain js

[1, [2, [3, [4]], 5]].flat()
// => [1, 2, [3, [4]], 5]
Resources: Array#flat Source

flattenDeep

lodash

// https://lodash.com/docs/#flattenDeep
import { flattenDeep } from 'lodash'

flattenDeep([1, [2, [3, [4]], 5]])
// => [1, 2, 3, 4, 5]

plain js

[1, [[2], [3, [4]], 5]].flat(Infinity)
// => [1, 2, 3, 4, 5]
Resources: Array#flat Source

fromPairs

lodash

// https://lodash.com/docs/#fromPairs
import { fromPairs } from 'lodash'

fromPairs([
  ['a', 1],
  ['b', 2],
])
// => { 'a': 1, 'b': 2 }

plain js

Object.fromEntries([
  ['a', 1],
  ['b', 2],
])
// => { 'a': 1, 'b': 2 }
Resources: Object.fromEntries

head

lodash

// https://lodash.com/docs/#head
import { head } from 'lodash'

head([1, 2, 3])
// => 1

plain js

const [head, ...tail] = [1, 2, 3]
head
// => 1
Resources: Spread syntax Source

indexOf

lodash

// https://lodash.com/docs/#indexOf
import { indexOf } from 'lodash'

indexOf([1, 2, 3], 3)
// => 2

plain js

[1, 2, 3].indexOf(3)
// => 2
Resources: Array#indexOf

initial

lodash

// https://lodash.com/docs/#initial
import { initial } from 'lodash'

initial([1, 2, 3])
// => [1, 2]

plain js

[1, 2, 3].slice(0, -1)
// => [1, 2]
Resources: Array#slice

intersection

lodash

// https://lodash.com/docs/#intersection
import { intersection } from 'lodash'

intersection([2, 1], [2, 3])
// => [2]

plain js

const intersection = (arr, ...args) =>
  arr.filter(item => args.every(arr => arr.includes(item)))

intersection([2, 1], [2, 3])
// => [2]
Resources: Spread syntax Array#filter Array#every

join

lodash

// https://lodash.com/docs/#join
import { join } from 'lodash'

join(['a', 'b', 'c'], '~')
// => 'a~b~c'

plain js

['a', 'b', 'c'].join('~')
// => 'a~b~c'
Resources: Array#join

last

lodash

// https://lodash.com/docs/#last
import { last } from 'lodash'

last(['a', 'b', 'c'])
// => 'c'

plain js

const arr = ['a', 'b', 'c']

arr[arr.length - 1]
// => 'c'

lastIndexOf

lodash

// https://lodash.com/docs/#lastIndexOf
import { lastIndexOf } from 'lodash'

lastIndexOf([1, 2, 1, 2], 2)
// => 3

// Search from the `fromIndex`
lastIndexOf([1, 2, 1, 2], 2, 2)
// => 1

plain js

[1, 2, 1, 2].lastIndexOf(2)
// => 3

// Search from the `fromIndex`
[1, 2, 1, 2].lastIndexOf(2, 2)
// => 1
Resources: Array#lastIndexOf

nth

lodash

// https://lodash.com/docs/#nth
import { nth } from 'lodash'

const array = ['a', 'b', 'c', 'd']

nth(array, 1)
// => 'b'

nth(array, -2)
// => 'c';

plain js

const nth = (arr, idx) => arr.slice(idx, idx + 1)[0]

const array = ['a', 'b', 'c', 'd']

nth(array, 1)
// => 'b'

nth(array, -2)
// => 'c';
Resources: Array#slice

pullAt

lodash

// https://lodash.com/docs/#pullAt
import { pullAt } from 'lodash'

const array = ['a', 'b', 'c', 'd']

pullAt(array, [1, 3])
// => ['b', 'd']

array
// => ['a', 'c']

plain js

const pullAt = (arr, idxs) =>
  idxs
    .reverse()
    .map(idx => arr.splice(idx, 1)[0])
    .reverse()

const array = ['a', 'b', 'c', 'd']

pullAt(array, [1, 3])
// => ['b', 'd']

array
// => ['a', 'c']
Resources: Array#reverse Array#splice

reject

lodash

// https://lodash.com/docs/#reject
import { reject } from 'lodash'

reject(
  ['a', 'b', 'c', 'd', 'e', 'f', 'g'],
  char => char === 'd'
)
// => [['a', 'b', 'c', 'e', 'f', 'g']]

plain js

['a', 'b', 'c', 'd', 'e', 'f', 'g'].filter(
  char => char !== 'd'
)
// => [['a', 'b', 'c', 'e', 'f', 'g']]
Resources: Array#filter

remove

lodash

// https://lodash.com/docs/#remove
import { remove } from 'lodash'

const array = [1, 2, 3, 4]
const evens = remove(array, n => {
  return n % 2 === 0
})

array
// => [1, 3]

evens
// => [2, 4]

const newArray = [1, 2, 3, 4, 5]

remove(newArray, () => newArray.length > 0)
// => [1, 2, 3, 4, 5]

newArray
// => []

plain js

const remove = (array, iteratee) => {
  // in order to not mutate the original array until the very end
  // we want to cache the indexes to remove while preparing the result to return
  const toRemove = []
  const result = array.filter((item, i) => iteratee(item) && toRemove.push(i))

  // just before returning, we can then remove the items, making sure we start
  // from the higher indexes: otherwise they would shift at each removal
  toRemove.reverse().forEach(i => array.splice(i, 1))
  return result
}

const array = [1, 2, 3, 4]
const evens = remove(array, n => {
  return n % 2 === 0
})

array
// => [1, 3]

evens
// => [2, 4]

const newArray = [1, 2, 3, 4, 5]

remove(newArray, () => newArray.length > 0)
// => [1, 2, 3, 4, 5]

newArray
// => []
Resources: Array#filter Array#splice

reverse

lodash

// https://lodash.com/docs/#reverse
import { reverse } from 'lodash'

const array = [1, 2, 3]

reverse(array)
// => [3, 2, 1]

array
// => [3, 2, 1]

plain js

const array = [1, 2, 3]

array.reverse()
// => [3, 2, 1]

array
// => [3, 2, 1]
Resources: Array#reverse

sortedIndexOf

lodash

// https://lodash.com/docs/#sortedIndexOf
import { sortedIndexOf } from 'lodash'

sortedIndexOf([4, 5, 5, 5, 6], 5)
// => 1

plain js

const sortedIndexOf = (arr, value) => [...arr].sort().indexOf(value)

sortedIndexOf([4, 5, 5, 5, 6], 5)
// => 1
Resources: Array#sort Array#indexOf

sortedLastIndexOf

lodash

// https://lodash.com/docs/#sortedLastIndexOf
import { sortedLastIndexOf } from 'lodash'

sortedLastIndexOf([4, 5, 5, 5, 6], 5)
// => 3

plain js

// https://lodash.com/docs/#sortedLastIndexOf
const sortedLastIndexOf = (arr, value) => [...arr].sort().lastIndexOf(value)

sortedLastIndexOf([4, 5, 5, 5, 6], 5)
// => 3
Resources: Array#sort Array#lastIndexOf

sortedUniq

lodash

// https://lodash.com/docs/#sortedUniq
import { sortedUniq } from 'lodash'

sortedUniq([1, 1, 2])
// => [1, 2]

plain js

const sortedUniq = arr => [...new Set(arr)].sort()

sortedUniq([1, 1, 2])
// => [1, 2]
Resources: Set Array#sort

tail

lodash

// https://lodash.com/docs/#tail
import { tail } from 'lodash'

tail([1, 2, 3])
// => [2, 3]

plain js

const [head, ...tail] = [1, 2, 3]
tail
// => [2, 3]
Resources: Spread syntax Source

take

lodash

// https://lodash.com/docs/#take
import { take } from 'lodash'

take([1, 2, 3])
// => [1]

take([1, 2, 3], 2)
// => [1, 2]

take([1, 2, 3], 5)
// => [1, 2, 3]

take([1, 2, 3], 0)
// => []

plain js

const take = (arr, qty = 1) => [...arr].splice(0, qty)

take([1, 2, 3])
// => [1]

take([1, 2, 3], 2)
// => [1, 2]

take([1, 2, 3], 5)
// => [1, 2, 3]

take([1, 2, 3], 0)
// => []
Resources: Default parameters Spread syntax Array#splice

takeRight

lodash

// https://lodash.com/docs/#takeRight
import { takeRight } from 'lodash'

takeRight([1, 2, 3])
// => [3]

takeRight([1, 2, 3], 2)
// => [2, 3]

takeRight([1, 2, 3], 5)
// => [1, 2, 3]

takeRight([1, 2, 3], 0)
// => []

plain js

const takeRight = (arr, qty = 1) => [...arr].splice(-qty, qty)

takeRight([1, 2, 3])
// => [3]

takeRight([1, 2, 3], 2)
// => [2, 3]

takeRight([1, 2, 3], 5)
// => [1, 2, 3]

takeRight([1, 2, 3], 0)
// => []
Resources: Default parameters Spread syntax Array#splice

toPairs

lodash

// https://lodash.com/docs/#toPairs
import { toPairs } from 'lodash'

function Foo() {
  this.a = 1
  this.b = 2
}

Foo.prototype.c = 3

toPairs(new Foo())
// => [['a', 1], ['b', 2]] (iteration order is not guaranteed)

plain js

function Foo() {
  this.a = 1
  this.b = 2
}

Foo.prototype.c = 3

Object.entries(new Foo())
// => [['a', 1], ['b', 2]] (iteration order is not guaranteed)
Resources: Object.entries

union

lodash

// https://lodash.com/docs/#union
import { union } from 'lodash'

union([2], [1, 2], [1, 2])
// => [2, 1]

plain js

const union = (arr, ...args) => [...new Set(arr.concat(...args))]

union([2], [1, 2], [1, 2])
// => [2, 1]
Resources: Spread syntax Set

uniq

lodash

// https://lodash.com/docs/#uniq
import { uniq } from 'lodash'

uniq([2, 1, 2])
// => [2, 1]

plain js

[...new Set([2, 1, 2])]
// => [2, 1]
Resources: Set Source

unzip

lodash

// https://lodash.com/docs/#unzip
import { unzip } from 'lodash'

unzip([
  ['a', 1, true],
  ['b', 2, false],
])
// => [['a', 'b'], [1, 2], [true, false]]

plain js

const zip = (arr, ...args) =>
  arr.map((value, idx) => [value, ...args.map(arr => arr[idx])])

const unzip = ([...args]) => zip(...args)

unzip([
  ['a', 1, true],
  ['b', 2, false],
])
// => [['a', 'b'], [1, 2], [true, false]]
Resources: Spread syntax Array#map

without

lodash

// https://lodash.com/docs/#without
import { without } from 'lodash'

const array = [2, 1, 2, 3]
without(array, 1, 2)
// => [3]

array
// => [2, 1, 2, 3]

plain js

const without = (arr, ...args) => arr.filter(item => !args.includes(item))

const array = [2, 1, 2, 3]

without(array, 1, 2)
// => [3]

array
// => [2, 1, 2, 3]
Resources: Spread syntax Array#filter Array#includes

zip

lodash

// https://lodash.com/docs/#zip
import { zip } from 'lodash'

zip(['a', 'b'], [1, 2], [true, false])
// => [['a', 1, true], ['b', 2, false]]

plain js

const zip = (arr, ...args) =>
  arr.map((value, idx) => [value, ...args.map(arr => arr[idx])])

zip(['a', 'b'], [1, 2], [true, false])
// => [['a', 1, true], ['b', 2, false]]
Resources: Spread syntax Array#map

zipObject

lodash

// https://lodash.com/docs/#zipObject
import { zipObject } from 'lodash'

zipObject(['a', 'b'], [1, 2])
// => { 'a': 1, 'b': 2 }

plain js

const zipObject = (keys, values) =>
  keys.reduce((acc, key, idx) => {
    acc[key] = values[idx]
    return acc
  }, {})

zipObject(['a', 'b'], [1, 2])
// => { 'a': 1, 'b': 2 }
Resources: Array#reduce

collection

every

lodash

// https://lodash.com/docs/#every
import { every } from 'lodash'

function isLargerThanTen(element) {
  return element >= 10
}

every([10, 20, 30], isLargerThanTen)
// => true

plain js

function isLargerThanTen(element) {
  return element >= 10
}

[10, 20, 30].every(isLargerThanTen)
// => true
Resources: Array#every Source

filter

lodash

// https://lodash.com/docs/#filter
import { filter } from 'lodash'

function isBigEnough(value) {
  return value >= 10
}

filter([12, 5, 8, 130, 44], isBigEnough)
// => [12, 130, 44]

plain js

function isBigEnough(value) {
  return value >= 10
}

[12, 5, 8, 130, 44].filter(isBigEnough)
// => [12, 130, 44]
Resources: Array#filter Source

find

lodash

// https://lodash.com/docs/#find
import { find } from 'lodash'

const users = [
  { user: 'barney', age: 36, active: true },
  { user: 'fred', age: 40, active: false },
  { user: 'pebbles', age: 1, active: true },
]

find(users, o => o.age < 40)
// => { user: "barney", age: 36, active: true }

plain js

const users = [
  { user: 'barney', age: 36, active: true },
  { user: 'fred', age: 40, active: false },
  { user: 'pebbles', age: 1, active: true },
]

users.find(o => o.age < 40)
// => { user: "barney", age: 36, active: true }
Resources: Array#find Source

forEach

lodash

// https://lodash.com/docs/#forEach
import { forEach } from 'lodash'

const array = ['a', 'b', 'c']

forEach(array, (item, index) => {
  console.log(item, index)
})
// => a 0
// => b 1
// => c 2

plain js

;['a', 'b', 'c'].forEach((item, index) => {
  console.log(item, index)
})
// => a 0
// => b 1
// => c 2
Resources: Array#forEach Source

forEachRight

lodash

// https://lodash.com/docs/#forEachRight
import { forEachRight } from 'lodash'

const array = ['a', 'b', 'c']

forEachRight(array, (item, index) => {
  console.log(item, index)
})
// => c 2
// => b 1
// => a 0

plain js

const forEachRight = (array, iteratee) =>
  [...array].reverse().forEach((val, index) => {
    iteratee(val, array.length - 1 - index, array)
  })

const array = ['a', 'b', 'c']

forEachRight(array, (item, index) => {
  console.log(item, index)
})
// => c 2
// => b 1
// => a 0
Resources: Spread syntax Array#reverse Array#forEach

includes

lodash

// https://lodash.com/docs/#includes
import { includes } from 'lodash'

includes([1, 2, 3], 1)
// => true

plain js

[1, 2, 3].includes(1)
// => true
Resources: Array#includes Source

map

lodash

// https://lodash.com/docs/#map
import { map } from 'lodash'

map([1, 2, 3], n => n * 3)
// => [3, 6, 9]

plain js

[1, 2, 3].map(n => n * 3)
// => [3, 6, 9]
Resources: Array#map Source

reduce

lodash

// https://lodash.com/docs/#reduce
import { reduce } from 'lodash'

reduce([1, 2], (sum, n) => sum + n, 0)
// => 3

reduce(
  { a: 1, b: 2, c: 1 },
  (result, value, key) => {
    ;(result[value] || (result[value] = [])).push(key)
    return result
  },
  {}
)
// => { '1': ['a', 'c'], '2': ['b'] } (iteration order is not guaranteed)

plain js

[1, 2].reduce((sum, n) => sum + n, 0)
// => 3

Object.entries({ a: 1, b: 2, c: 1 }).reduce(
  (result, [key, value]) => {
    ;(result[value] || (result[value] = [])).push(key)
    return result
  },
  {}
)
// => { '1': ['a', 'c'], '2': ['b'] } (iteration order is not guaranteed)
Resources: Object.entries Array#reduce

reduceRight

lodash

// https://lodash.com/docs/#reduceRight
import { reduceRight } from 'lodash'

reduceRight(
  [
    [0, 1],
    [2, 3],
    [4, 5],
  ],
  (flattened, other) => flattened.concat(other),
  []
)
// => [4, 5, 2, 3, 0, 1]

plain js

[
  [0, 1],
  [2, 3],
  [4, 5],
].reduceRight((flattened, other) => flattened.concat(other), [])
// => [4, 5, 2, 3, 0, 1]
Resources: Array#reduceRight Source

size

lodash

// https://lodash.com/docs/#size
import { size } from 'lodash'

size([1, 2, 3])
// => 3

size({ a: 1, b: 2 })
// => 2

size('pebbles')
// => 7

plain js

const size = item =>
  item.constructor === Object ? Object.keys(item).length : item.length

size([1, 2, 3])
// => 3

size({ a: 1, b: 2 })
// => 2

size('pebbles')
// => 7
Resources: Object.keys Source

some

lodash

// https://lodash.com/docs/#some
import { some } from 'lodash'

const isEven = n => n % 2 === 0

some([3, 4, 5], isEven)
// => true

plain js

const isEven = n => n % 2 === 0

[3, 4, 5].some(isEven)
// => true
Resources: Array#some

date

now

lodash

// https://lodash.com/docs/#now
import { now } from 'lodash'

now()
// => # milliseconds  elapsed since the Unix epoch

plain js

Date.now()
// => # milliseconds  elapsed since the Unix epoch
Resources: Date.now

function

ary

lodash

// https://lodash.com/docs/#ary
import { ary } from 'lodash'

['6', '8', '10'].map(ary(Number.parseInt, 1))
// => [6, 8, 10]

plain js

const ary = (fn, arity) => (...args) => fn(...args.slice(0, arity))

['6', '8', '10'].map(ary(Number.parseInt, 1))
// => [6, 8, 10]
Resources: Spread syntax

curry

lodash

// https://lodash.com/docs/#curry
import { curry } from 'lodash'

const abc = (a, b, c) => [a, b, c]

const curried = curry(abc)

curried(1)(2)(3)
// => [1, 2, 3]

curried(1, 2)(3)
// => [1, 2, 3]

curried(1, 2, 3)
// => [1, 2, 3]

plain js

const curry = func => {
  // define the number of expected arguments
  const expectedArgs = func.length
  const curried = (...args) => {
    // if enough arugments has been passed return the
    // result of the function execution, otherwise
    // continue adding arguments to the list
    return args.length >= expectedArgs
      ? func(...args)
      : (...args2) => curried(...args.concat(args2))
  }
  return curried
}

const abc = (a, b, c) => [a, b, c]

const curried = curry(abc)

curried(1)(2)(3)
// => [1, 2, 3]

curried(1, 2)(3)
// => [1, 2, 3]

curried(1, 2, 3)
// => [1, 2, 3]
Resources: Spread syntax learn-js

curryRight

lodash

// https://lodash.com/docs/#curryRight
import { curryRight } from 'lodash'

const abc = (a, b, c) => [a, b, c]

const curried = curryRight(abc)

curried(3)(2)(1)
// => [1, 2, 3]

curried(2, 3)(1)
// => [1, 2, 3]

curried(1, 2, 3)
// => [1, 2, 3]

plain js

// the only difference from the curry method
// implementation is how arguments gets concatenated
const curryRight = func => {
  const expectedArgs = func.length
  const curried = (...args) => {
    return args.length >= expectedArgs
      ? func(...args)
      : (...args2) => curried(...args2.concat(args))
  }
  return curried
}

const abc = (a, b, c) => [a, b, c]

const curried = curryRight(abc)

curried(3)(2)(1)
// => [1, 2, 3]

curried(2, 3)(1)
// => [1, 2, 3]

curried(1, 2, 3)
// => [1, 2, 3]
Resources: learn-js

flip

lodash

// https://lodash.com/docs/#flip
import { flip } from 'lodash'

const flipped = flip((...args) => args)

flipped('a', 'b', 'c', 'd')
// => ['d', 'c', 'b', 'a']

plain js

const flip = func => (...args) => func(...args.reverse())

const flipped = flip((...args) => args)

flipped('a', 'b', 'c', 'd')
// => ['d', 'c', 'b', 'a']
Resources: Spread syntax

negate

lodash

// https://lodash.com/docs/#negate
import { negate } from 'lodash'

const isEven = n => n % 2 === 0

[1, 2, 3, 4, 5, 6].filter(negate(isEven))
// => [1, 3, 5]

plain js

const negate = func => (...args) => !func(...args)

const isEven = n => n % 2 === 0

[1, 2, 3, 4, 5, 6].filter(negate(isEven))
// => [1, 3, 5]
Resources: Spread syntax

partial

lodash

// https://lodash.com/docs/#partial
import { partial } from 'lodash'

const greet = (greeting, name) => `${greeting} ${name}`

const sayHelloTo = partial(greet, 'hello')
sayHelloTo('fred')
// => 'hello fred'

plain js

const partial = (func, ...args) => (...furtherArgs) =>
  func(...args, ...furtherArgs)

const greet = (greeting, name) => `${greeting} ${name}`

const sayHelloTo = partial(greet, 'hello')
sayHelloTo('fred')
// => 'hello fred'

partialRight

lodash

// https://lodash.com/docs/#partialRight
import { partialRight } from 'lodash'

const greet = (greeting, name) => `${greeting} ${name}`

const greetFred = partialRight(greet, 'fred')
greetFred('hi')
// => 'hi fred'

plain js

const partialRight = (func, ...cachedArgs) => (...args) =>
  func(...args, ...cachedArgs)

const greet = (greeting, name) => `${greeting} ${name}`

const greetFred = partialRight(greet, 'fred')
greetFred('hi')
// => 'hi fred'
Resources: Spread syntax

rearg

lodash

// https://lodash.com/docs/#rearg
import { rearg } from 'lodash'

const rearged = rearg((a, b, c) => [a, b, c], [2, 0, 1])

rearged('b', 'c', 'a')
// => ['a', 'b', 'c']

plain js

const rearg = (func, order) => (...args) => {
  const reargs = order.map(idx => args[idx])
  return func(...reargs)
}

const rearged = rearg((a, b, c) => [a, b, c], [2, 0, 1])

rearged('b', 'c', 'a')
// => ['a', 'b', 'c']
Resources: Spread syntax

unary

lodash

// https://lodash.com/docs/#unary
import { unary } from 'lodash'

['6', '8', '10'].map(unary(Number.parseInt))
// => [6, 8, 10]

plain js

const unary = fn => arg => fn(arg)

['6', '8', '10'].map(unary(Number.parseInt))
// => [6, 8, 10]

wrap

lodash

// https://lodash.com/docs/#wrap
import { wrap } from 'lodash'

const sum2 = wrap(2, (a, b, c) => {
  return a + b + c
})

sum2(1, 2)
// => 5

plain js

const wrap = (value, func) => (...args) => func(value, ...args)

const sum2 = wrap(2, (a, b, c) => {
  return a + b + c
})

sum2(1, 2)
// => 5
Resources: Spread syntax

lang

castArray

lodash

// https://lodash.com/docs/#castArray
import { castArray } from 'lodash'

castArray(1)
// => [1]

castArray({ a: 1 })
// => [{ 'a': 1 }]

castArray('abc')
// => ['abc']

castArray(null)
// => [null]

castArray(undefined)
// => [undefined]

castArray()
// => []

const array = [1, 2, 3]
castArray(array) === array
// => true

plain js

const castArray = (...args) => (args[0] instanceof Array ? args[0] : args)

castArray(1)
// => [1]

castArray({ a: 1 })
// => [{ 'a': 1 }]

castArray('abc')
// => ['abc']

castArray(null)
// => [null]

castArray(undefined)
// => [undefined]

castArray()
// => []

const array = [1, 2, 3]
castArray(array) === array
// => true
Resources: instanceof Spread syntax

conformsTo

lodash

// https://lodash.com/docs/#conformsTo
import { conformsTo } from 'lodash'

const object = { a: 1, b: 2 }

conformsTo(object, {
  b: n => n > 1,
})
// => true

conformsTo(object, {
  b: n => n > 2,
})
// => false

plain js

const conformsTo = (obj, ruleSet) =>
  Object.keys(ruleSet).every(key => ruleSet[key](obj[key]))

const object = { a: 1, b: 2 }

conformsTo(object, {
  b: n => n > 1,
})
// => true

conformsTo(object, {
  b: n => n > 2,
})
// => false
Resources: Object.keys Array#every

gt

lodash

// https://lodash.com/docs/#gt
import { gt } from 'lodash'

gt(3, 1)
// => true

gt(3, 3)
// => false

gt(1, 3)
// => false

plain js

const gt = (a, b) => a > b

gt(3, 1)
// => true

gt(3, 3)
// => false

gt(1, 3)
// => false
Resources: Comparison Operators

gte

lodash

// https://lodash.com/docs/#gte
import { gte } from 'lodash'

gte(3, 1)
// => true

gte(3, 3)
// => true

gte(1, 3)
// => false

plain js

const gte = (a, b) => a >= b

gte(3, 1)
// => true

gte(3, 3)
// => true

gte(1, 3)
// => false
Resources: Comparison Operators

isArray

lodash

// https://lodash.com/docs/#isArray
import { isArray } from 'lodash'

isArray([1, 2, 3])
// => true

isArray(document.body.children)
// => false

isArray('abc')
// => false

plain js

Array.isArray([1, 2, 3])
// => true

Array.isArray(document.body.children)
// => false

Array.isArray('abc')
// => false
Resources: Array.isArray

isBoolean

lodash

// https://lodash.com/docs/#isBoolean
import { isBoolean } from 'lodash'

isBoolean(false)
// => true

isBoolean(null)
// => false

plain js

const isBoolean = arg => arg === !!arg

isBoolean(false)
// => true

isBoolean(null)
// => false

isDate

lodash

// https://lodash.com/docs/#isDate
import { isDate } from 'lodash'

isDate(new Date())
// => true

isDate('Mon April 23 2012')
// => false

plain js

const isDate = d => d instanceof Date && !isNaN(d)

isDate(new Date())
// => true

isDate('Mon April 23 2012')
// => false
Resources: instanceof

isError

lodash

// https://lodash.com/docs/#isError
import { isError } from 'lodash'

isError(new Error())
// => true

isError(Error)
// => false

plain js

const isError = err => err instanceof Error

isError(new Error())
// => true

isError(Error)
// => false
Resources: instanceof

isFinite

lodash

// https://lodash.com/docs/#isFinite
import { isFinite } from 'lodash'

isFinite(3)
// => true

isFinite(Number.MIN_VALUE)
// => true

isFinite(Infinity)
// => false

isFinite('3')
// => false

plain js

Number.isFinite(3)
// => true

Number.isFinite(Number.MIN_VALUE)
// => true

Number.isFinite(Infinity)
// => false

Number.isFinite('3')
// => false
Resources: Number.isFinite

isInteger

lodash

// https://lodash.com/docs/#isInteger
import { isInteger } from 'lodash'

isInteger(3)
// => true

isInteger(Number.MIN_VALUE)
// => false

isInteger(Infinity)
// => false

isInteger('3')
// => false

plain js

Number.isInteger(3)
// => true

Number.isInteger(Number.MIN_VALUE)
// => false

Number.isInteger(Infinity)
// => false

Number.isInteger('3')
// => false
Resources: Number.isInteger

isNaN

lodash

// https://lodash.com/docs/#isNaN
import { isNaN } from 'lodash'

isNaN(NaN)
// => true

isNaN(Number(NaN))
// => true

isNaN(undefined)
// => false

plain js

Number.isNaN(NaN)
// => true

Number.isNaN(Number(NaN))
// => true

Number.isNaN(undefined)
// => false
Resources: Number.isNaN

isNil

lodash

// https://lodash.com/docs/#isNil
import { isNil } from 'lodash'

isNil(null)
// => true

isNil(undefined)
// => true

isNil(NaN)
// => false

plain js

const isNil = val => val == null

isNil(null)
// => true

isNil(undefined)
// => true

isNil(NaN)
// => false
Resources: Comparison Operators

isNull

lodash

// https://lodash.com/docs/#isNull
import { isNull } from 'lodash'

isNull(null)
// => true

isNull(undefined)
// => false

plain js

const isNull = val => val === null

isNull(null)
// => true

isNull(undefined)
// => false
Resources: Equality comparisons

isNumber

lodash

// https://lodash.com/docs/#isNumber
import { isNumber } from 'lodash'

isNumber(3)
// => true

isNumber(Number.MIN_VALUE)
// => true

isNumber(Infinity)
// => true

isNumber('3')
// => false

plain js

const isNumber = a => typeof a === 'number'

isNumber(3)
// => true

isNumber(Number.MIN_VALUE)
// => true

isNumber(Infinity)
// => true

isNumber('3')
// => false
Resources: typeof

isObject

lodash

// https://lodash.com/docs/#isObject
import { isObject } from 'lodash'

isObject({})
// => true

isObject([1, 2, 3])
// => true

isObject(() => {})
// => true

isObject(null)
// => false

plain js

const isObject = a => a instanceof Object

isObject({})
// => true

isObject([1, 2, 3])
// => true

isObject(() => {})
// => true

isObject(null)
// => false
Resources: instanceof

isRegExp

lodash

// https://lodash.com/docs/#isRegExp
import { isRegExp } from 'lodash'

isRegExp(/abc/)
// => true

isRegExp('/abc/')
// => false

plain js

const isRegExp = obj => obj instanceof RegExp

isRegExp(/abc/)
// => true

isRegExp('/abc/')
// => false
Resources: instanceof

isString

lodash

// https://lodash.com/docs/#isString
import { isString } from 'lodash'

isString('abc')
// => true

isString(1)
// => false

plain js

const isString = a => typeof a === 'string'

isString('abc')
// => true

isString(1)
// => false
Resources: typeof

isUndefined

lodash

// https://lodash.com/docs/#isUndefined
import { isUndefined } from 'lodash'

isUndefined(undefined)
// => true

isUndefined(null)
// => false

plain js

const isUndefined = val => val === undefined

isUndefined(undefined)
// => true

isUndefined(null)
// => false
Resources: Equality comparisons

lt

lodash

// https://lodash.com/docs/#lt
import { lt } from 'lodash'

lt(1, 3)
// => true

lt(3, 3)
// => false

lt(3, 1)
// => false

plain js

const lt = (a, b) => a < b

lt(1, 3)
// => true

lt(3, 3)
// => false

lt(3, 1)
// => false
Resources: Comparison Operators

lte

lodash

// https://lodash.com/docs/#lte
import { lte } from 'lodash'

lte(1, 3)
// => true

lte(3, 3)
// => true

lte(3, 1)
// => false

plain js

const lte = (a, b) => a <= b

lte(1, 3)
// => true

lte(3, 3)
// => false

lte(3, 1)
// => false
Resources: Comparison Operators

math

add

lodash

// https://lodash.com/docs/#add
import { add } from 'lodash'

add(6, 4)
// => 10

plain js

const add = (a, b) => a + b

add(6, 4)
// => 10

ceil

lodash

// https://lodash.com/docs/#ceil
import { ceil } from 'lodash'

ceil(4.006)
// => 5

ceil(6.004, 2)
// => 6.01

ceil(6040, -2)
// => 6100

plain js

const ceil = (num, precision) => {
  const modifier = 10 ** precision
  return Math.ceil(num * modifier) / modifier
}

Math.ceil(4.006)
// => 5

ceil(6.004, 2)
// => 6.01

ceil(6040, -2)
// => 6100
Resources: Assignment Operators

divide

lodash

// https://lodash.com/docs/#divide
import { divide } from 'lodash'

divide(6, 4)
// => 1.5

plain js

const divide = (a, b) => a / b

divide(6, 4)
// => 1.5

floor

lodash

// https://lodash.com/docs/#floor
import { floor } from 'lodash'

floor(4.006)
// => 4

floor(0.046, 2)
// => 0.04

floor(4060, -2)
// => 4000

plain js

const floor = (num, precision) => {
  const modifier = 10 ** precision
  return Math.floor(num * modifier) / modifier
}

Math.floor(4.006)
// => 4

floor(0.046, 2)
// => 0.04

floor(4060, -2)
// => 4000
Resources: Assignment Operators

max

lodash

// https://lodash.com/docs/#max
import { max } from 'lodash'

max([4, 2, 8, 6])
// => 8

max([])
// => undefined

plain js

const max = nums => {
  if (nums.length) return Math.max(...nums)
}

max([4, 2, 8, 6])
// => 8

max([])
// => undefined
Resources: Spread syntax

maxBy

lodash

// https://lodash.com/docs/#maxBy
import { maxBy } from 'lodash'

const objects = [{ n: 1 }, { n: 2 }]

maxBy(objects, o => o.n)
// => { 'n': 2 }

plain js

const maxBy = (arr, func) => {
  const max = Math.max(...arr.map(func))
  return arr.find(item => func(item) === max)
}

const objects = [{ n: 1 }, { n: 2 }]

maxBy(objects, o => o.n)
// => { 'n': 2 }
Resources: Spread syntax

mean

lodash

// https://lodash.com/docs/#mean
import { mean } from 'lodash'

mean([4, 2, 8, 6])
// => 5

plain js

const mean = arr => arr.reduce((acc, num) => acc + num, 0) / arr.length

mean([4, 2, 8, 6])
// => 5
Resources: Array#reduce

meanBy

lodash

// https://lodash.com/docs/#meanBy
import { meanBy } from 'lodash'

const objects = [{ n: 4 }, { n: 2 }, { n: 8 }, { n: 6 }]

meanBy(objects, o => o.n)
// => 5

plain js

const meanBy = (arr, func) =>
  arr.reduce((acc, item) => acc + func(item), 0) / arr.length

const objects = [{ n: 4 }, { n: 2 }, { n: 8 }, { n: 6 }]

meanBy(objects, o => o.n)
// => 5
Resources: Array#reduce

min

lodash

// https://lodash.com/docs/#min
import { min } from 'lodash'

min([4, 2, 8, 6])
// => 2

min([])
// => undefined

plain js

const min = nums => {
  if (nums.length) return Math.min(...nums)
}

min([4, 2, 8, 6])
// => 2

min([])
// => undefined
Resources: Spread syntax

minBy

lodash

// https://lodash.com/docs/#minBy
import { minBy } from 'lodash'

const objects = [{ n: 1 }, { n: 2 }]

minBy(objects, o => o.n)
// => { 'n': 1 }

plain js

const minBy = (arr, func) => {
  const min = Math.min(...arr.map(func))
  return arr.find(item => func(item) === min)
}

const objects = [{ n: 1 }, { n: 2 }]

minBy(objects, o => o.n)
// => { 'n': 1 }
Resources: Spread syntax

multiply

lodash

// https://lodash.com/docs/#multiply
import { multiply } from 'lodash'

multiply(6, 4)
// => 24

plain js

const multiply = (a, b) => a * b

multiply(6, 4)
// => 24

round

lodash

// https://lodash.com/docs/#round
import { round } from 'lodash'

round(4.006)
// => 4

round(4.006, 2)
// => 4.01

round(4060, -2)
// => 4100

plain js

const round = (num, precision) => {
  const modifier = 10 ** precision
  return Math.round(num * modifier) / modifier
}

Math.round(4.006)
// => 4

round(4.006, 2)
// => 4.01

round(4060, -2)
// => 4100
Resources: Assignment Operators

subtract

lodash

// https://lodash.com/docs/#subtract
import { subtract } from 'lodash'

subtract(6, 4)
// => 2

plain js

const subtract = (a, b) => a - b

subtract(6, 4)
// => 2

sum

lodash

// https://lodash.com/docs/#sum
import { sum } from 'lodash'

sum([4, 2, 8, 6])
// => 20

plain js

[4, 2, 8, 6].reduce((acc, num) => {
  acc += num
  return acc
}, 0)
// => 20
Resources: Array#reduce

sumBy

lodash

// https://lodash.com/docs/#sumBy
import { sumBy } from 'lodash'

const objects = [{ n: 4 }, { n: 2 }, { n: 8 }, { n: 6 }]

sumBy(objects, o => o.n)
// => 20

plain js

const sumBy = (arr, func) => arr.reduce((acc, item) => acc + func(item), 0)

const objects = [{ n: 4 }, { n: 2 }, { n: 8 }, { n: 6 }]

sumBy(objects, o => o.n)
// => 20
Resources: Array#reduce

number

clamp

lodash

// https://lodash.com/docs/#clamp
import { clamp } from 'lodash'

clamp(-10, -5)
// => -10

clamp(-10, -5, 5)
// => -5

clamp(10, -5, 5)
// => 5

plain js

const clamp = (num, clamp, higher) =>
  higher ? Math.min(Math.max(num, clamp), higher) : Math.min(num, clamp)

clamp(-10, -5)
// => -10

clamp(-10, -5, 5)
// => -5

clamp(10, -5, 5)
// => 5

inRange

lodash

// https://lodash.com/docs/#inRange
import { inRange } from 'lodash'

inRange(3, 2, 4)
// => true

inRange(4, 8)
// => true

inRange(4, 2)
// => false

inRange(2, 2)
// => false

inRange(1.2, 2)
// => true

inRange(5.2, 4)
// => false

inRange(-3, -2, -6)
// => true

plain js

const inRange = (num, rangeStart, rangeEnd = 0) =>
  (rangeStart < num && num < rangeEnd) || (rangeEnd < num && num < rangeStart)

inRange(3, 2, 4)
// => true

inRange(4, 8)
// => true

inRange(4, 2)
// => false

inRange(2, 2)
// => false

inRange(1.2, 2)
// => true

inRange(5.2, 4)
// => false

inRange(-3, -2, -6)
// => true
Resources: Default parameters

object

assign

lodash

// https://lodash.com/docs/#assign
import { assign } from 'lodash'

function Foo() {
  this.a = 1
}

function Bar() {
  this.c = 3
}

Foo.prototype.b = 2
Bar.prototype.d = 4

assign({ a: 0 }, new Foo(), new Bar())
// => { 'a': 1, 'c': 3 }

plain js

function Foo() {
  this.a = 1
}

function Bar() {
  this.c = 3
}

Foo.prototype.b = 2
Bar.prototype.d = 4

{ a: 0, ...new Foo(), ...new Bar() }
// => { 'a': 1, 'c': 3 }
Resources: Spread syntax

create

lodash

// https://lodash.com/docs/#create
import { create } from 'lodash'

function Shape() {
  this.x = 0
  this.y = 0
}

function Circle() {
  Shape.call(this)
}

Circle.prototype = create(Shape.prototype, {
  constructor: Circle,
})

const circle = new Circle()
circle instanceof Circle
// => true

circle instanceof Shape
// => true

plain js

function Shape() {
  this.x = 0
  this.y = 0
}

function Circle() {
  Shape.call(this)
}

Circle.prototype = Object.assign(Object.create(Shape.prototype), {
  constructor: Circle,
})

const circle = new Circle()
circle instanceof Circle
// => true

circle instanceof Shape
// => true
Resources: Object.assign Object.create instanceof

defaults

lodash

// https://lodash.com/docs/#defaults
import { defaults } from 'lodash'

defaults({ a: 1 }, { b: 2 }, { a: 3 })
// // => { 'a': 1, 'b': 2 }

plain js

const defaults = (...args) =>
  args.reverse().reduce((acc, obj) => ({ ...acc, ...obj }), {})

defaults({ a: 1 }, { b: 2 }, { a: 3 })
// // => { 'a': 1, 'b': 2 }
Resources: Spread syntax Array#reverse Array#reduce

get

lodash

// https://lodash.com/docs/#get
import { get } from 'lodash'

const simpleObject = { a: { b: 2 } }
const complexObject = { a: [{ bar: { c: 3 } }] }

get(simpleObject, 'a.b')
// => 2
get(complexObject, 'a[0].bar.c')
// => 3
get(complexObject, ['a', '0', 'bar', 'c'])
// => 2
get(simpleObject, 'a.bar.c', 'default')
// => 'default'
get(complexObject, 'a.bar.c', 'default')
// =>  'default'
get(complexObject, null)
// =>  undefined

plain js

const get = (obj, path, defValue) => {
  // If path is not defined or it has false value
  if (!path) return undefined
  // Check if path is string or array. Regex : ensure that we do not have '.' and brackets.
  // Regex explained: https://regexr.com/58j0k
  const pathArray = Array.isArray(path) ? path : path.match(/([^[.\]])+/g)
  // Find value if exist return otherwise return undefined value;
  return (
    pathArray.reduce((prevObj, key) => prevObj && prevObj[key], obj) || defValue
  )
}

const simpleObject = { a: { b: 2 } }
const complexObject = { a: [{ bar: { c: 3 } }] }

get(simpleObject, 'a.b')
// => 2
get(complexObject, 'a[0].bar.c')
// => 3
get(complexObject, ['a', '0', 'bar', 'c'])
// => 2
get(simpleObject, 'a.bar.c', 'default')
// => 'default'
get(complexObject, 'a.bar.c', 'default')
// =>  'default
get(complexObject, null)
// =>  undefined
Resources: Array.isArray Array#reduce Array#filter xkcd

has

lodash

// https://lodash.com/docs/#has
import { has } from 'lodash'

const object = { a: { bar: 2 } }

has(object, 'a')
// => true

has(object, 'a.bar')
// => true

has(object, ['a', 'bar'])
// => true

has(object, ['a', 'c'])
// => false

plain js

const has = (obj, path) => {
  // Regex explained: https://regexr.com/58j0k
  const pathArray = Array.isArray(path) ? path : path.match(/([^[.\]])+/g)

  return !!pathArray.reduce((prevObj, key) => prevObj && prevObj[key], obj)
}

const object = { a: { bar: 2 } }

has(object, 'a')
// => true

has(object, 'a.bar')
// => true

has(object, ['a', 'bar'])
// => true

has(object, ['a', 'c'])
// => false
Resources: Array.isArray Array#reduce xkcd

invert

lodash

// https://lodash.com/docs/#invert
import { invert } from 'lodash'

const object = { a: 1, b: 2, c: 1 }

invert(object)
// => { '1': 'c', '2': 'b' }

plain js

const object = { a: 1, b: 2, c: 1 }

Object.entries(object).reduce(
  (acc, [key, value]) => ({
    ...acc,
    [value]: key,
  }),
  {}
)

// => { '1': 'c', '2': 'b' }
Resources: Object.entries Spread syntax Array#reduce

keys

lodash

// https://lodash.com/docs/#keys
import { keys } from 'lodash'

function Foo() {
  this.a = 1
  this.b = 2
}

Foo.prototype.c = 3

keys(new Foo())
// => ['a', 'b'] (iteration order is not guaranteed)

keys('hi')
// => ['0', '1']

plain js

function Foo() {
  this.a = 1
  this.b = 2
}

Foo.prototype.c = 3

Object.keys(new Foo())
// => ['a', 'b'] (iteration order is not guaranteed)

Object.keys('hi')
// => ['0', '1']
Resources: Object.keys

mapKeys

lodash

// https://lodash.com/docs/#mapKeys
import { mapKeys } from 'lodash'

mapKeys({ a: 1, b: 2 }, (value, key) => key + value)
// => { 'a1': 1, 'b2': 2 }

plain js

const mapKeys = (obj, mapper) =>
  Object.entries(obj).reduce(
    (acc, [key, value]) => ({
      ...acc,
      [mapper(value, key)]: value,
    }),
    {}
  )

mapKeys({ a: 1, b: 2 }, (value, key) => key + value)
// => { 'a1': 1, 'b2': 2 }
Resources: Object.entries Array#reduce Spread syntax Computed property names

omit

lodash

// https://lodash.com/docs/#omit
import { omit } from 'lodash'

const object = { a: 1, b: '2', c: 3 }

omit(object, ['a', 'c'])
// => { 'b': '2' }

plain js

const omit = (obj, props) => {
  obj = { ...obj }
  props.forEach(prop => delete obj[prop])
  return obj
}
const object = { a: 1, b: '2', c: 3 }

omit(object, ['a', 'c'])
// => { 'b': '2' }
Resources: Spread syntax Array#forEach Delete operator

omitBy

lodash

// https://lodash.com/docs/#omitBy
import { omitBy, isNumber } from 'lodash'

const object = { a: 1, b: '2', c: 3 }

omitBy(object, isNumber)
// => { 'b': '2' }

plain js

const isNumber = a => typeof a === 'number'

const omitBy = (obj, check) => {
  obj = { ...obj }
  Object.entries(obj).forEach(([key, value]) => check(value) && delete obj[key])
  return obj
}

const object = { a: 1, b: '2', c: 3 }

omitBy(object, isNumber)
// => { 'b': '2' }
Resources: Spread syntax Object.entries Array#forEach Delete operator

pick

lodash

// https://lodash.com/docs/#pick
import { pick } from 'lodash'

const object = {
  a: 1,
  b: 2,
  c: 3,
}

pick(object, ['a', 'c'])
// => {a: 1, c: 3}

plain js

const object = {
  a: 1,
  b: 2,
  c: 3,
}

const { a, c } = object

{ a, c }
// => {a: 1, c: 3}
Resources: Object destructuring

set

lodash

// https://lodash.com/docs/#set
import { set } from 'lodash'

const object = { a: [{ bar: { c: 3 } }] }

set(object, 'a[0].bar.c', 4)
object.a[0].bar.c
// => 4

set(object, ['x', '0', 'y', 'z'], 5)
object.x[0].y.z
// => 5

plain js

const set = (obj, path, value) => {
  // Regex explained: https://regexr.com/58j0k
  const pathArray = Array.isArray(path) ? path : path.match(/([^[.\]])+/g)

  pathArray.reduce((acc, key, i) => {
    if (acc[key] === undefined) acc[key] = {}
    if (i === pathArray.length - 1) acc[key] = value
    return acc[key]
  }, obj)
}

const object = { a: [{ bar: { c: 3 } }] }

set(object, 'a[0].bar.c', 4)
object.a[0].bar.c
// => 4

set(object, ['x', '0', 'y', 'z'], 5)
object.x[0].y.z
// => 5
Resources: Array.isArray Array#reduce xkcd

unset

lodash

// https://lodash.com/docs/#unset
import { unset } from 'lodash'

const object = { a: [{ bar: { c: 7, d: 6 } }] }

unset(object, 'a[0].bar.c')
object
// => { 'a': [{ 'bar': { 'd': 6 } }] };

plain js

const unset = (obj, path) => {
  // Regex explained: https://regexr.com/58j0k
  const pathArray = Array.isArray(path) ? path : path.match(/([^[.\]])+/g)

  pathArray.reduce((acc, key, i) => {
    if (i === pathArray.length - 1) delete acc[key]
    return acc[key]
  }, obj)
}
const object = { a: [{ bar: { c: 7, d: 6 } }] }

unset(object, 'a[0].bar.c')
object
// => { 'a': [{ 'bar': { 'd': 6 } }] };
Resources: Array.isArray Array#reduce Delete operator xkcd

values

lodash

// https://lodash.com/docs/#values
import { values } from 'lodash'

const object = {
  0: {
    a: 1,
    b: 2,
    c: 3,
  },
  1: {
    d: 4,
    e: 5,
    f: 6,
  },
}

values(object)
// => [{a: 1, b: 2, c: 3}, {d: 4, e: 5, f: 6}]

plain js

const object = {
  0: {
    a: 1,
    b: 2,
    c: 3,
  },
  1: {
    d: 4,
    e: 5,
    f: 6,
  },
}

Object.values(object)
// => [{a: 1, b: 2, c: 3}, {d: 4, e: 5, f: 6}]
Resources: Object.values

string

capitalize

lodash

// https://lodash.com/docs/#capitalize
import { capitalize } from 'lodash'

capitalize('FRED')
// => 'Fred'

plain js

const capitalize = str =>
  `${str.charAt(0).toUpperCase()}${str.slice(1).toLowerCase()}`

capitalize('FRED')
// => 'Fred'
Resources: String#charAt String#slice

endsWith

lodash

// https://lodash.com/docs/#endsWith
import { endsWith } from 'lodash'

endsWith('pinecone', 'cone')
// => true

plain js

'pinecone'.endsWith('cone')
// => true
Resources: endsWith

lowerFirst

lodash

// https://lodash.com/docs/#lowerFirst
import { lowerFirst } from 'lodash'

lowerFirst('Fred')
// => 'fred'

lowerFirst('FRED')
// => 'fRED'

plain js

const lowerFirst = str => `${str.charAt(0).toLowerCase()}${str.slice(1)}`

lowerFirst('Fred')
// => 'fred'

lowerFirst('FRED')
// => 'fRED'
Resources: String#charAt String#slice

pad

lodash

// https://lodash.com/docs/#pad
import { pad } from 'lodash'

pad('abc', 8)
// // => '  abc   '
//
pad('abc', 8, '_-')
// // => '_-abc_-_'
//
pad('abc', 3)
// // => 'abc'

plain js

const pad = (str, pad, custom) => {
  const prePad = Math.floor((pad - str.length) / 2) + str.length
  return str.padStart(prePad, custom).padEnd(pad, custom)
}

pad('abc', 8)
// // => '  abc   '
//
pad('abc', 8, '_-')
// // => '_-abc_-_'
//
pad('abc', 3)
// // => 'abc'
Resources: String#padStart String#padEnd

padEnd

lodash

// https://lodash.com/docs/#padEnd
import { padEnd } from 'lodash'

padEnd('abc', 6)
// => 'abc   '

padEnd('abc', 6, '_-')
// => 'abc_-_'

padEnd('abc', 3)
// => 'abc'

plain js

'abc'.padEnd(6)
// => 'abc   '

'abc'.padEnd(6, '_-')
// => 'abc_-_'

'abc'.padEnd(3)
// => 'abc'
Resources: String#padEnd

padStart

lodash

// https://lodash.com/docs/#padStart
import { padStart } from 'lodash'

padStart('abc', 6)
// => '   abc'

padStart('abc', 6, '_-')
// => '_-_abc'

padStart('abc', 3)
// => 'abc'

plain js

'abc'.padStart(6)
// => '   abc'

'abc'.padStart(6, '_-')
// => '_-_abc'

'abc'.padStart(3)
// => 'abc'
Resources: String#padStart

parseInt

lodash

// https://lodash.com/docs/#parseInt
import { parseInt } from 'lodash'

parseInt('08')
// => 8

['6', '08', '10'].map(parseInt)
// => [6, 8, 10]

plain js

parseInt('08', 10)
// => 8

['6', '08', '10'].map(i => parseInt(i, 10))
// => [6, 8, 10]
Resources: parseInt

repeat

lodash

// https://lodash.com/docs/#repeat
import { repeat } from 'lodash'

repeat('*', 3)
// => '***'

repeat('abc', 2)
// => 'abcabc'

repeat('abc', 0)
// => ''

plain js

'*'.repeat(3)
// => '***'

'abc'.repeat(2)
// => 'abcabc'

'abc'.repeat(0)
// => ''
Resources: String#repeat

replace

lodash

// https://lodash.com/docs/#replace
import { replace } from 'lodash'

replace('Hi Fred', 'Fred', 'Barney')
// => 'Hi Barney'

plain js

const replace = (str, s, r) => str.replace(s, r)

replace('Hi Fred', 'Fred', 'Barney')
// => 'Hi Barney'
Resources: String#replace

split

lodash

// https://lodash.com/docs/#split
import { split } from 'lodash'

split('a-b-c', '-')
// => ['a', 'b', 'c']

split('a-b-c', '-', 2)
// => ['a', 'b']

plain js

'a-b-c'.split('-')
// => ['a', 'b', 'c']

'a-b-c'.split('-').slice(0, 2)
// => ['a', 'b']
Resources: String#split

startsWith

lodash

// https://lodash.com/docs/#startsWith
import { startsWith } from 'lodash'

startsWith('JavaScript', 'Java')
// => true

plain js

'JavaScript'.startsWith('Java')
// => true
Resources: String#startsWith

toLower

lodash

// https://lodash.com/docs/#toLower
import { toLower } from 'lodash'

toLower('--Foo-Bar--')
// => '--foo-bar--'

toLower('fooBar')
// => 'foobar'

toLower('__FOO_BAR__')
// => '__foo_bar__'

plain js

const toLower = str => str.toLowerCase()

toLower('--foo-bar--')
// => '--foo-bar--'

toLower('fooBar')
// => 'foobar'

toLower('__foo_bar__')
// => '__foo_bar__'

trim

lodash

// https://lodash.com/docs/#trim
import { trim } from 'lodash'

trim(' abc ')
// => 'abc'

trim('-_-abc-_-', '_-')
// => 'abc'

[' foo ', ' bar '].map(trim)
// => ['foo', 'bar']

plain js

// Regex explained: https://regexr.com/4v6jg
const trim = (str, c = '\\s') =>
  str.replace(new RegExp(`^([${c}]*)(.*?)([${c}]*)$`), '$2')

' abc '.trim()
// => 'abc'

trim('-_-abc-_-', '_-')
// => 'abc'

[' foo ', ' bar '].map(s => trim(s))
// => ['foo', 'bar']
Resources: xkcd

trimEnd

lodash

// https://lodash.com/docs/#trimEnd
import { trimEnd } from 'lodash'

trimEnd(' abc ')
// => ' abc'

trimEnd('-_-abc-_-', '_-')
// => '-_-abc'

plain js

// Regex explained: https://regexr.com/4v6iu
const trimEnd = (str, c = '\\s') =>
  str.replace(new RegExp(`^(.*?)([${c}]*)$`), '$1')

' abc '.trimEnd()
// => ' abc'

trimEnd(' abc ')
// => ' abc'

trimEnd('-_-abc-_-', '_-')
// => '-_-abc'
Resources: xkcd

trimStart

lodash

// https://lodash.com/docs/#trimStart
import { trimStart } from 'lodash'

trimStart(' abc ')
// => 'abc '

trimStart('-_-abc-_-', '_-')
// => 'abc-_-'

plain js

// Regex explained: https://regexr.com/4v6j7
const trimStart = (str, c = '\\s') =>
  str.replace(new RegExp(`^([${c}]*)(.*)$`), '$2')

' abc '.trimStart()
// => 'abc '

trimStart(' abc ')
// => 'abc '

trimStart('-_-abc-_-', '_-')
// => 'abc-_-'
Resources: xkcd

upperFirst

lodash

// https://lodash.com/docs/#upperFirst
import { upperFirst } from 'lodash'

upperFirst('fred')
// => 'Fred'

upperFirst('FRED')
// => 'FRED'

plain js

const upperFirst = str => `${str.charAt(0).toUpperCase()}${str.slice(1)}`

upperFirst('fred')
// => 'Fred'

upperFirst('FRED')
// => 'FRED'
Resources: String#charAt String#slice

util

attempt

lodash

// https://lodash.com/docs/#attempt
import { attempt } from 'lodash'

attempt(item => item.split(''), 'string')
// => ["s", "t", "r", "i", "n", "g"]

attempt(item => item.split(''), 1)
// => [TypeError: item.split is not a function]

plain js

const attempt = (func, ...args) => {
  try {
    return func(...args)
  } catch (e) {
    return e
  }
}

attempt(item => item.split(''), 'string')
// => ["s", "t", "r", "i", "n", "g"]

attempt(item => item.split(''), 1)
// => [TypeError: item.split is not a function]
Resources: Spread syntax try…catch

constant

lodash

// https://lodash.com/docs/#constant
import { constant } from 'lodash'

const return42 = constant(42)
return42()
// => 42

plain js

const constant = arg => () => arg
const return42 = constant(42)

return42()
// => 42

defaultTo

lodash

// https://lodash.com/docs/#defaultTo
import { defaultTo } from 'lodash'

defaultTo(1, 10)
// => 1

defaultTo('', 10)
// => ''

defaultTo(undefined, 10)
defaultTo(null, 10)
defaultTo(NaN, 10)
// => 10

plain js

const defaultTo = (a, b) => (a == null || Object.is(a, NaN) ? b : a)

defaultTo(1, 10)
// => 1

defaultTo('', 10)
// => ''

defaultTo(undefined, 10)
defaultTo(null, 10)
defaultTo(NaN, 10)
// => 10
Resources: Object.is

flow

lodash

// https://lodash.com/docs/#flow
import { flow } from 'lodash'

const add = (a, b) => a + b

const square = n => n * n

const addSquare = flow([add, square])
addSquare(1, 2)
// => 9

plain js

const flow = funcs => (...args) =>
  funcs.reduce((prev, fnc) => [fnc(...prev)], args)[0]

const add = (a, b) => a + b

const square = n => n * n

const addSquare = flow([add, square])
addSquare(1, 2)
// => 9
Resources: Spread syntax Array#reduce

flowRight

lodash

// https://lodash.com/docs/#flowRight
import { flowRight } from 'lodash'

function add(a, b) {
  return a + b
}

function square(n) {
  return n * n
}

const addSquare = flowRight([square, add])
addSquare(1, 2)
// => 9

plain js

const flowRight = funcs => (...args) =>
  funcs.reverse().reduce((prev, fnc) => [fnc(...prev)], args)[0]

const add = (a, b) => a + b

const square = n => n * n

const addSquare = flowRight([square, add])
addSquare(1, 2)
// => 9
Resources: Spread syntax Array#reduce

identity

lodash

// https://lodash.com/docs/#identity
import { identity } from 'lodash'

const object = { a: 1 }

identity(object) === object
// => true

plain js

const identity = a => a

const object = { a: 1 }

identity(object) === object
// => true

noop

lodash

// https://lodash.com/docs/#noop
import { noop } from 'lodash'

noop()
// => undefined

plain js

const noop = () => {}

noop()
// => undefined

nthArg

lodash

// https://lodash.com/docs/#nthArg
import { nthArg } from 'lodash'

let func = nthArg(1)
func('a', 'b', 'c', 'd')
// => 'b'

func = nthArg(-2)
func('a', 'b', 'c', 'd')
// => 'c'

plain js

const nthArg = idx => (...args) => args.slice(idx, idx + 1)[0]

let func = nthArg(1)
func('a', 'b', 'c', 'd')
// => 'b'

func = nthArg(-2)
func('a', 'b', 'c', 'd')
// => 'c'
Resources: Spread syntax Array#slice

over

lodash

// https://lodash.com/docs/#over
import { over } from 'lodash'

const func = over([Math.max, Math.min])

func(1, 2, 3, 4)
// => [4, 1]

plain js

const over = arr => (...args) => arr.map(func => func(...args))

const func = over([Math.max, Math.min])

func(1, 2, 3, 4)
// => [4, 1]
Resources: Spread syntax Array#map

overEvery

lodash

// https://lodash.com/docs/#overEvery
import { overEvery } from 'lodash'

const func = overEvery([Boolean, isFinite])

func('1')
// => true

func(null)
// => false

func(NaN)
// => false

plain js

const overSome = checks => item => checks.every(check => check(item))

const func = overSome([Boolean, isFinite])

func('1')
// => true

func(null)
// => false

func(NaN)
// => false
Resources: Array#every

overSome

lodash

// https://lodash.com/docs/#overSome
import { overSome } from 'lodash'

const func = overSome([Boolean, isFinite])

func('1')
// => true

func(null)
// => true

func(NaN)
// => false

plain js

const overSome = checks => item => checks.some(check => check(item))

const func = overSome([Boolean, isFinite])

func('1')
// => true

func(null)
// => true

func(NaN)
// => false
Resources: Array#some

stubArray

lodash

// https://lodash.com/docs/#stubArray
import { stubArray } from 'lodash'

stubArray()
// => []

plain js

const stubArray = () => []

stubArray()
// => []

stubFalse

lodash

// https://lodash.com/docs/#stubFalse
import { stubFalse } from 'lodash'

stubFalse()
// => false

plain js

const stubFalse = () => false

stubFalse()
// => false

stubObject

lodash

// https://lodash.com/docs/#stubObject
import { stubObject } from 'lodash'

stubObject()
// => {}

plain js

const stubObject = () => ({})

stubObject()
// => {}

stubString

lodash

// https://lodash.com/docs/#stubString
import { stubString } from 'lodash'

stubString()
// => ''

plain js

const stubString = () => ''

stubString()
// => ''

stubTrue

lodash

// https://lodash.com/docs/#stubTrue
import { stubTrue } from 'lodash'

stubTrue()
// => true

plain js

const stubTrue = () => true

stubTrue()
// => true

times

lodash

// https://lodash.com/docs/#times
import { times } from 'lodash'

times(3)
// => [0, 1, 2]

times(3, i => i + 3)
// => [3, 4, 5]

plain js

const times = (n, func = i => i) =>
  Array.from({ length: n }).map((_, i) => func(i))

times(3)
// => [0, 1, 2]

times(3, i => i + 3)
// => [3, 4, 5]
Resources: Array.from Array#map

uniqueId

lodash

// https://lodash.com/docs/#uniqueId
import { uniqueId } from 'lodash'

uniqueId('contact_')
// => 'contact_1'

uniqueId()
// => '2'

plain js

const uniqueId = (counter => (str = '') => `${str}${++counter}`)(0)

uniqueId('contact_')
// => 'contact_1'

uniqueId()
// => '2'
Resources: IIFE